Topic: Templates and trivial conversions?
Author: g2devi@cdf.toronto.edu (Deviasse Robert N.)
Date: Sun, 6 Jun 1993 17:15:44 GMT Raw View
I know that ARM explicitly states that not even trivial conversions are applied
in order to match a template, but I also know that there has been some effort
to relax this rigid restriction. I'm curious whether the following example
has been deemed legal yet:
template<class T>
struct Ptr{
Ptr(T* p) {}
};
struct A { A(){} };
struct BA : public A { BA(){} };
struct EBA : public BA { EBA() {} };
void test(Ptr<A>) { cout << "A*" << endl; }
void test(Ptr<BA>) { cout << "BA*" << endl; }
int main(){
EBA* eba;
test(eba); // Both this
test(Ptr(eba)); // and this generate compile-time errors
return 0;
}
It seems fairly obvious that a conversion to Ptr<BA> is desired in the above,
but both my compiler and ARM (as I understand it) say that the above is not
legal. Has the ANSI committee decided whether the above is legal or not yet?
Take care
Robert
--
/----------------------------------+------------------------------------------\
| Robert N. Deviasse |"If we have to re-invent the wheel, |
| EMAIL: g2devi@cdf.utoronto.ca | can we at least make it round this time"|
+----------------------------------+------------------------------------------/
Author: pete@borland.com (Pete Becker)
Date: Sun, 6 Jun 1993 19:30:21 GMT Raw View
In article <1993Jun6.171544.15025@cdf.toronto.edu> g2devi@cdf.toronto.edu (Deviasse Robert N.) writes:
>
>I know that ARM explicitly states that not even trivial conversions are applied
>in order to match a template, but I also know that there has been some effort
>to relax this rigid restriction. I'm curious whether the following example
>has been deemed legal yet:
>
> template<class T>
> struct Ptr{
> Ptr(T* p) {}
> };
>
>
> struct A { A(){} };
> struct BA : public A { BA(){} };
> struct EBA : public BA { EBA() {} };
>
> void test(Ptr<A>) { cout << "A*" << endl; }
> void test(Ptr<BA>) { cout << "BA*" << endl; }
>
> int main(){
> EBA* eba;
> test(eba); // Both this
> test(Ptr(eba)); // and this generate compile-time errors
> return 0;
> }
>
>
>It seems fairly obvious that a conversion to Ptr<BA> is desired in the above,
>but both my compiler and ARM (as I understand it) say that the above is not
>legal. Has the ANSI committee decided whether the above is legal or not yet?
>
This has nothing to do with trivial conversions. There is no conversion
whatsoever between a Ptr<EBA> and a Ptr<BA>. Those two classes have nothing
to do with each other.
-- Pete
Author: g2devi@cdf.toronto.edu (Deviasse Robert N.)
Date: Mon, 7 Jun 1993 00:32:03 GMT Raw View
In article <1993Jun6.193021.22210@borland.com> pete@borland.com (Pete Becker) writes:
>In article <1993Jun6.171544.15025@cdf.toronto.edu> g2devi@cdf.toronto.edu (Deviasse Robert N.) writes:
>>
>>I know that ARM explicitly states that not even trivial conversions are applied
>>in order to match a template, but I also know that there has been some effort
>>to relax this rigid restriction. I'm curious whether the following example
>>has been deemed legal yet:
>>
>> template<class T>
>> struct Ptr{
>> Ptr(T* p) {}
>> };
>>
>>
>> struct A { A(){} };
>> struct BA : public A { BA(){} };
>> struct EBA : public BA { EBA() {} };
>>
>> void test(Ptr<A>) { cout << "A*" << endl; }
>> void test(Ptr<BA>) { cout << "BA*" << endl; }
>>
>> int main(){
>> EBA* eba;
>> test(eba); // Both this
>> test(Ptr(eba)); // and this generate compile-time errors
>> return 0;
>> }
>>
>>
>>It seems fairly obvious that a conversion to Ptr<BA> is desired in the above,
>>but both my compiler and ARM (as I understand it) say that the above is not
>>legal. Has the ANSI committee decided whether the above is legal or not yet?
>>
>
> This has nothing to do with trivial conversions. There is no conversion
>whatsoever between a Ptr<EBA> and a Ptr<BA>. Those two classes have nothing
>to do with each other.
> -- Pete
>
But both of the following *are* legal:
test((BA*)eba);
test(Ptr<BA>(eba));
There is no matching test(Ptr<EBA>), I was asking whether the trivial conversion
of EBA* -> BA* would be attempted next. If this is the case, then we have a
match. and
test(eba);
compiles okay. Extending this argument, the case
test(Ptr(eba));
does not match any function so that perhaps
test(Ptr((BA*)eba));
should be tried, and *this* matches the same function as above. (I know, I'm
*really* stretching the argument.)
I realize that there is nothing trivial about implementing templates, and
some form of backtracking would probably be needed if the above were accepted.
I would definitely understand if the committee decided to disallow the above
conversions. Despite this, I asked the question because I think that the
above conversions would be useful and wondered if the committee thought they
were *useful enough* to be part of the standard.
Take care
Robert
--
/----------------------------------+------------------------------------------\
| Robert N. Deviasse |"If we have to re-invent the wheel, |
| EMAIL: g2devi@cdf.utoronto.ca | can we at least make it round this time"|
+----------------------------------+------------------------------------------/
Author: thomson@cppfs.torolab.ibm.com (Brian Thomson)
Date: 7 Jun 1993 21:28:56 GMT Raw View
In article <1993Jun6.171544.15025@cdf.toronto.edu> g2devi@cdf.toronto.edu (Deviasse Robert N.) writes:
>
>I know that ARM explicitly states that not even trivial conversions are applied
>in order to match a template, but I also know that there has been some effort
>to relax this rigid restriction. I'm curious whether the following example
>has been deemed legal yet:
>
> template<class T>
> struct Ptr{
> Ptr(T* p) {}
> };
>
>
> struct A { A(){} };
> struct BA : public A { BA(){} };
> struct EBA : public BA { EBA() {} };
>
> void test(Ptr<A>) { cout << "A*" << endl; }
> void test(Ptr<BA>) { cout << "BA*" << endl; }
>
> int main(){
> EBA* eba;
> test(eba); // Both this
> test(Ptr(eba)); // and this generate compile-time errors
> return 0;
> }
>
>
>It seems fairly obvious that a conversion to Ptr<BA> is desired in the above,
>but both my compiler and ARM (as I understand it) say that the above is not
>legal. Has the ANSI committee decided whether the above is legal or not yet?
IBM's C++ compilers reject both lines, but for different reasons.
Neither really has anything to do with template matching.
The test(eba) call is ambiguous, because the EBA* may be converted
to either a BA* or an A*, then converted again by using the constructors
of the (already instantiated!) template classes Ptr<A> and PTR<BA>, to
match the non-template functions test(Ptr<A>) and test(Ptr<BA>),
respectively.
The second line is simply syntactically incorrect. Ptr may not be
used all by itself as a type name, it needs an argument enclosed by
angle brackets.
What exactly were you expecting to happen for these two lines?
--
Brian Thomson THOMSON at TOROLAB
OS/2 C++ Development thomson@vnet.ibm.com
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Mon, 7 Jun 1993 23:29:33 GMT Raw View
In article <1993Jun6.171544.15025@cdf.toronto.edu> g2devi@cdf.toronto.edu (Deviasse Robert N.) writes:
>
>I know that ARM explicitly states that not even trivial conversions are applied
>in order to match a template...
Buzzztt! Wrong.
Tha ARM talks about an "exact match" between the types of template formals
and the types of template actuals... where the term "exact match" is
defined in the chapter on overloading.
Surprizing as it may be to some, you can have an "exact match" even though
you use some trivial conversions.
--
// Ron ("Loose Cannon") Guilmette uucp: ...uunet!lupine!segfault!rfg
//
// "On the one hand I knew that programs could have a compelling
// and deep logical beauty, on the other hand I was forced to
// admit that most programs are presented in a way fit for
// mechanical execution, but even if of any beauty at all,
// totally unfit for human appreciation."
// -- Edsger W. Dijkstra
Author: g2devi@cdf.toronto.edu (Deviasse Robert N.)
Date: 8 Jun 93 01:50:01 GMT Raw View
In article <1v0buo$b96@tornews.torolab.ibm.com> thomson@cppfs.torolab.ibm.com (Brian Thomson) writes:
>In article <1993Jun6.171544.15025@cdf.toronto.edu> g2devi@cdf.toronto.edu (Deviasse Robert N.) writes:
>>
>>I know that ARM explicitly states that not even trivial conversions are applied
>>in order to match a template, but I also know that there has been some effort
>>to relax this rigid restriction. I'm curious whether the following example
>>has been deemed legal yet:
>>
>> template<class T>
>> struct Ptr{
>> Ptr(T* p) {}
>> };
>>
>>
>> struct A { A(){} };
>> struct BA : public A { BA(){} };
>> struct EBA : public BA { EBA() {} };
>>
>> void test(Ptr<A>) { cout << "A*" << endl; }
>> void test(Ptr<BA>) { cout << "BA*" << endl; }
>>
>> int main(){
>> EBA* eba;
>> test(eba); // Both this
>> test(Ptr(eba)); // and this generate compile-time errors
>> return 0;
>> }
>>
>>
>>It seems fairly obvious that a conversion to Ptr<BA> is desired in the above,
>>but both my compiler and ARM (as I understand it) say that the above is not
>>legal. Has the ANSI committee decided whether the above is legal or not yet?
>
>IBM's C++ compilers reject both lines, but for different reasons.
>Neither really has anything to do with template matching.
>
>The test(eba) call is ambiguous, because the EBA* may be converted
>to either a BA* or an A*, then converted again by using the constructors
>of the (already instantiated!) template classes Ptr<A> and PTR<BA>, to
>match the non-template functions test(Ptr<A>) and test(Ptr<BA>),
>respectively.
>
>The second line is simply syntactically incorrect. Ptr may not be
>used all by itself as a type name, it needs an argument enclosed by
>angle brackets.
>
>What exactly were you expecting to happen for these two lines?
What you described! My question was not whether these two lines were legal
by the specification in ARM, they are clearly not. I was asking if any
decisions on extending templates in the ways I described. I didn't have
much hope for the second example, it was put in half by mistake. It would
have no problem matching uniquely under Prolog, but then again C++ templates
are not matched by Prolog rules. Somehow I suspect that compiler writers would
balk at having to use parse templates using prolog rules:-)
The first example was the one I was more concerned with. I would have wanted
eba (of type EBA*) to be converted to Ptr<BA*> in preference to Ptr<A*>.
However, Jamshid Afshar pointed out that this not a problem with templates
as the below example shows:
struct A {};
struct B : A {};
struct C : B {};
struct P { P(A*); };
struct Q { Q(B*); };
void f(P);
void f(Q);
main() {
C* c = new C;
f((B*)c); // okay (1)
f((A*)c); // okay (2)
f(c); // ambiguous: convert to P or Q? (3)
}
Actually, cases (1) and (3) are ambiguous in my compiler! Here it's pretty
obvious that f(Q) should be function we wanted f(c) to match. There's a lot
of technology behind automatic conversions so I'm sure there are technical
reasons for choosing the conversion rules so that this ambiguity exists.
>--
>Brian Thomson THOMSON at TOROLAB
>OS/2 C++ Development thomson@vnet.ibm.com
Take care.
Robert
--
/----------------------------------+------------------------------------------\
| Robert N. Deviasse |"If we have to re-invent the wheel, |
| EMAIL: g2devi@cdf.utoronto.ca | can we at least make it round this time"|
+----------------------------------+------------------------------------------/
Author: jamshid@emx.cc.utexas.edu (Jamshid Afshar)
Date: 7 Jun 1993 21:35:52 -0500 Raw View
In article <rfgC89yLA.I3y@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
>In article <1993Jun6.171544.15025@cdf.toronto.edu> g2devi@cdf.toronto.edu (Deviasse Robert N.) writes:
>>I know that ARM explicitly states that not even trivial conversions are
>>applied in order to match a template...
>
>Buzzztt! Wrong.
No, Robert is right about that. ANSI C++ might change this ARM rule,
though.
>Tha ARM talks about an "exact match" between the types of template formals
>and the types of template actuals... where the term "exact match" is
>defined in the chapter on overloading.
>Surprizing as it may be to some, you can have an "exact match" even though
>you use some trivial conversions.
You're right that an "exact match" as defined by the ARM 13.2 includes
trivial conversions, but take a closer look at ARM 14.4c:
[...] Overloading resolution for template functions and other
functions of the same name is done in three steps:
[1] Look for an exact match on functions; if found, call it.
[2] Look for a function template from which a function that
can be called with an exact match can be generated; if
^^^^^
found, call it.
[3] Try ordinary overloading resolution for the functions;
if a function is found, call it.
[...]
A match on a template (step [2]) implies that a specific
template function with arguments that exactly matches the types
of the arguments will be generated. Not even trivial conversions
^^^^^^^^^^^^^^^^^^^^^^^^
will be applied in this case.
The underlined "exact" is therefore meant literally. Lippman writes
in the _C++ Primer 2nd Ed_ 4.2 p199 that performing trivial
conversions is a likely ANSI extension. The BC++ for OS/2 README file
states that it now performs trivial conversions to match template
functions for compatibility with this CFRONT 3.0 "extension". The
README further states:
2) Derived class pointer or references arguments are permitted to
match their public base classes. For example:
template<class T> class B {};
template<class T> class D : public B<T> {};
template<class T> void foo(B<T> *b);
foo(new D<int>); // This is illegal under ANSI C++: unresolved
// foo(D<int> *). However, Borland C++ now
// allows foo(B<int> *) to be called.
This possible ANSI C++ extension is also implemented by CFRONT and
discussed in Primer2 9.3 p493. That's great, but I'm disturbed by the
README's sidenote:
The conversion from derived class to base class is allowed
only for template parameters, non-template parameters still
require exact matches. For example:
class B {};
class D : public B {};
template<class T> void bar(T ignored, B *b);
bar(0, new D); // Illegal under CFRONT 3.0, ANSI C++ and
// Borland C++: unresolved external bar(int, D *),
// D * -> B * is not considered an exact match.
Is allowing this not a likely ANSI C++ extension, or is Borland just
being very cautious? I was hoping ANSI would fix the common error:
#include <iostream.h>
template<class T> class List {/*...*/};
template<class T> ostream& operator<<(ostream&,const List<T>&);
main() {
List<int> list;
//...
cout << list << endl; // error (unfortunately)
}
I believe CFRONT implements this extension, but Borland and gcc do
not.
Jamshid Afshar
jamshid@emx.utexas.edu
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Tue, 8 Jun 1993 07:17:36 GMT Raw View
In article <1v0tu8INNiiv@emx.cc.utexas.edu> jamshid@emx.cc.utexas.edu (Jamshid Afshar) writes:
>In article <rfgC89yLA.I3y@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
>>In article <1993Jun6.171544.15025@cdf.toronto.edu> g2devi@cdf.toronto.edu (Deviasse Robert N.) writes:
>>>I know that ARM explicitly states that not even trivial conversions are
>>>applied in order to match a template...
>>
>>Buzzztt! Wrong.
>
>No, Robert is right about that. ANSI C++ might change this ARM rule,
>though.
>
>>Tha ARM talks about an "exact match" between the types of template formals
>>and the types of template actuals... where the term "exact match" is
>>defined in the chapter on overloading.
>>Surprizing as it may be to some, you can have an "exact match" even though
>>you use some trivial conversions.
>
>You're right that an "exact match" as defined by the ARM 13.2 includes
>trivial conversions, but take a closer look at ARM 14.4c:
...
> of the arguments will be generated. Not even trivial conversions
> ^^^^^^^^^^^^^^^^^^^^^^^^
You are right. I stand corrected.
Obviously, I missed that particular fine point.
In my own defense however, I would like just to note that the rule you have
cited is nonsensical anyway, and ought to go. I say it is nonsensical
because it is inconsistant. Why have such a special rule *only* for
function tempates and not for class templates?? (See 14.1) That is
rather silly.
>The underlined "exact" is therefore meant literally. Lippman writes
>in the _C++ Primer 2nd Ed_ 4.2 p199 that performing trivial
>conversions is a likely ANSI extension.
I should hope so, since it is permitted in the case of class templates.
--
// Ron ("Loose Cannon") Guilmette uucp: ...uunet!lupine!segfault!rfg
//
// "On the one hand I knew that programs could have a compelling
// and deep logical beauty, on the other hand I was forced to
// admit that most programs are presented in a way fit for
// mechanical execution, but even if of any beauty at all,
// totally unfit for human appreciation."
// -- Edsger W. Dijkstra
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Tue, 8 Jun 1993 16:00:42 GMT Raw View
In article <rfgC8AK9D.xG@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
>>You're right that an "exact match" as defined by the ARM 13.2 includes
>>trivial conversions, but take a closer look at ARM 14.4c:
>...
>> of the arguments will be generated. Not even trivial conversions
>> ^^^^^^^^^^^^^^^^^^^^^^^^
>
>You are right. I stand corrected.
>
>Obviously, I missed that particular fine point.
>
>In my own defense however, I would like just to note that the rule you have
>cited is nonsensical anyway, and ought to go. I say it is nonsensical
>because it is inconsistant. Why have such a special rule *only* for
>function tempates and not for class templates?? (See 14.1) That is
>rather silly.
Because for class templates there is no matching at all:
you have to instantiate a class template explicitly.
I guess the reason the ARM required an exact match was
that Bjarne wasn't sure of the right rules, and so used the most
conservative one so as to allow it to be relaxed later.
That is under consideration by the committee now.
Defining suitable relaxed rules is quite hard, and complicated
by what I consider a flawed concept of type inherent in the language.
For example:
template<class T> f(T x) { .. }
int x;
int &y=x;
f(x);
f(y);
If the call f(y) sets T==int& we're in trouble. Writing the words
to prevent this is hard because C++ considers references distinct
types (I dont).
I expect (hope?) that considerations by the extensions
working group of type inference (thats what this is) with respect
to extension to the template mechanism will greatly aid in
resolving core issues of the type system.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA