Topic: Problem with function template overload resolution


Author: jhrwalter@yahoo.com (Joerg Walter)
Date: Wed, 24 Sep 2003 15:23:13 +0000 (UTC)
Raw View
Dear Chris,

you wrote:

> > > I've already tried to discuss the following two programs on
> > > comp.lang.c++.moderated. Kresimir Fresl's test case
> > >
> > > ----------
> > > #include <iostream>
> > >
> > > template<typename A, typename T>
> > > struct result {};
> > >
> > > template<typename T>
> > > struct arg1 {
> > >    typedef T value_type;
> > > };
> > > template<typename T>
> > > struct arg2 {
> > >    typedef T value_type;
> > > };
> > >
> > > template<typename A>
> > > result<A, typename A::value_type> foo(A const& a) {
> > >    std::cout << "foo<A>" << std::endl;
> > >    return result<A, typename A::value_type>();
> > > }
> > > template<typename R, typename A>
> > > R foo(A const& a) {
> > >    std::cout << "foo<R, A>" << std::endl;
> > >    return R();
> > > }
> > >
> > > int main() {
> > >    arg1<int> s1;
> > >    arg2<int> s2;
> > >
> > >    foo(s2);    // OK
> > >
> > >    foo<arg1<int>, arg2<int> >(s2);  // OK
> > >    foo<arg2<int>, arg2<int> >(s2);  // OK
> > >
> > >    foo<arg1<int> >(s2);    // OK
> > >    foo<arg2<int> >(s2);    // Ambigous?
> > > }
> > >
> > > ----------
> > >
> > > is accepted by GCC 3.3.1, a program run results in
> > >
> > > foo<A>
> > > foo<R, A>
> > > foo<R, A>
> > > foo<R, A>
> > > foo<R, A>
> > >
> > > ICC 7.1 and MSVC 7.1 reject this code.
> >
> > And Comeau C/C++ 4.3.0.1, too.
> >
> > Some time ago (in January) I asked Comeau's support team about
> > it. Here is their reply:
> > ================================================================
> > [...] We suspect your case
> > is ill-formed but still need to go through that Standard more
> > thoroughly on it before saying so for certain, and we also want
> > to double check it is not impacted by any pending defect report.
> > ================================================================
> >
> > But they never said `so for certain', and, if `so', why.
> >
> > Regards,
> >
> > Kresimir Fresl
> >
> >
> > PS. I also tried 4.3.3 beta online:
> >
> >     http://www.comeaucomputing.com/tryitout/
> >
>
> According to the Standard (chapter about type deduction for partial
> specialized templates) there is no such thing as partial specialization
> for functions (yet).

We're not talking about partial specializations but about the interference
of explicit specification with argument deduction as far as I understand
14.1.8 bullet 2:

----------
Trailing template arguments that can be deduced (14.8.2) may be omitted from
the list of explicit template-arguments. ...
----------

> The closest thing you can get your hands on to is
> overloading. Thanks to A. Alexandrescu here is a neat idea which puts this
> into action:

[snip some Alexandrescu stuff ;-)]

> The honor of this idea & example go to Andrei, a real template guru!
>
> HTH

No.

Best,
Joerg

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Patrick.Kowalzick@cern.ch ("Patrick Kowalzick")
Date: Wed, 24 Sep 2003 15:24:29 +0000 (UTC)
Raw View
Dear all,

I just took my example to test what Chris proposed. Now I have code which
behaves different on several compilers (but it compiles) - LOL. Very nice.

The code changes:
-Introducing second function parameter (like proposed) but with default
argument
-Two more calls.

The code:

// ***** CODE *****

#include <iostream>

// no basic types to avoid automatic casting
class arg_1 {};
class arg_2 {};

// CHANGE:
template<typename A> void foo(A const& a ,A const& = A())
{
   std::cout << "foo<A>" << std::endl;
}

// CHANGE:
template<typename R, typename A> void foo(A const& a,R const& = R())
{
   std::cout << "foo<R, A>" << std::endl;
}

int main() {

 foo ( arg_1() );

 foo < arg_1 > ( arg_1() );  // should be no difference in deducing
 foo < arg_2 > ( arg_1() );  // which function to call

// CHANGE:
 foo < arg_1 > ( arg_1() , arg_1() );  // should call foo<A>
 foo < arg_2 > ( arg_1() , arg_2() );  // should call foo<R,A>

 foo< arg_1 , arg_1 > ( arg_1() );  // OK
 // foo< arg_1 , arg_2 > ( arg_1() );  // no casting from 1 to 2
 foo< arg_2 , arg_1 > ( arg_1() );  // OK
 // foo< arg_2 , arg_2 > ( arg_1() );  // no casting from 1 to 2

}

// ***** CODE ENDS *****


Results:

Perhaps using the defaulte parameters is not a good idea. But with the
default parameters the same functions should be called like with the version
before. So g++ behaves consistent, bcc not and why the hell MSVC is now able
to compile - LOL.

Anyway the version with the second parameter seems to work, and if the
second parameter is not a default parameter it should be quite safe.

-g++ 3.2.?

foo<A>
foo<R, A>
foo<R, A>
foo<A>
foo<R, A>
foo<R, A>
foo<R, A>


-bcc32 and MSVC 7.1

foo<A>
foo<A>
foo<R, A>
foo<A>
foo<R, A>
foo<R, A>
foo<R, A>


Regards, Patrick


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Christian.Theis@nospam.cern.ch ("Chris Theis")
Date: Fri, 26 Sep 2003 17:28:59 +0000 (UTC)
Raw View
"Joerg Walter" <jhrwalter@yahoo.com> wrote in message
news:4e6fccc6.0309231302.4c6a4a9f@posting.google.com...

> We're not talking about partial specializations but about the interference
> of explicit specification with argument deduction as far as I understand
> 14.1.8 bullet 2:
>
> ----------
> Trailing template arguments that can be deduced (14.8.2) may be omitted
from
> the list of explicit template-arguments. ...
> ----------

AFAIK the compiler is not required to deduce the argument the way you write
your second overloading. It would need to instantiate a type and this might
become a very complex task with regard to possible recursions. There has
been a patch to the gnu compiler which actually resolves the problem for a
case like yours.

[SNIP]
>
> No.
>

Take a deep breath buddy and relax. There's no need for snapping at me
trying to help you out.

Chris


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: fresl@grad.hr (Kresimir Fresl)
Date: Sat, 27 Sep 2003 01:18:24 +0000 (UTC)
Raw View
I wrote:

> Joerg Walter wrote:

>> I've already tried to discuss the following two programs on
>> comp.lang.c++.moderated. Kresimir Fresl's test case
[...]
>> is accepted by GCC 3.3.1, a program run results in
[...]
>> ICC 7.1 and MSVC 7.1 reject this code.

> And Comeau C/C++ 4.3.0.1, too.
>
> Some time ago (in January) I asked Comeau's support team about
> it. Here is their reply:
> ================================================================
> [...] We suspect your case
> is ill-formed but still need to go through that Standard more
> thoroughly on it before saying so for certain, and we also want
> to double check it is not impacted by any pending defect report.
> ================================================================
>
> But they never said `so for certain', and, if `so', why.

Yesterday I received the following mail from Comeau Computing:
================================================================
================================================================
At 10:39 AM 1/14/2003 +0100, Kresimir Fresl wrote:

> Following program cannot be compiled with
> Comeau C/C++ 4.3.0.1:
>
> ==========================================
> template <typename A, typename T>
> struct result {};
>
> template <typename A>
> result<A, typename A::val_t> func (A const& a) {
>    return result<A, typename A::val_t>();
> }
> template <typename R, typename A>
> R func (A const& a) {
>    return R();
> }
>
> template <typename T>
> struct str1 {
>    typedef T val_t;
> };
> template <typename T>
> struct str2 {
>    typedef T val_t;
> };
>
> int main() {
>    str1<int> s1;
>    str2<int> s2;
>
>    func (s1);    // OK
>    func (s2);    // OK
>
>    func<str1<int> > (s1);   // error1
>    func<str2<int> > (s1);   // OK
>    func<str1<int> > (s2);   // OK
>    func<str2<int> > (s2);   // error2
> }
> ==========================================
> error1: more than one instance of overloaded
>            function "func" matches the argument list:
>              function template "func(const A &)"
>              function template "func<R,A>(const A &)"
>              argument types are: (str1<int>)
>      func<str1<int> > (s1);
> error2: more than one instance of overloaded
>            function "func" matches the argument list:
>              function template "func(const A &)"
>              function template "func<R,A>(const A &)"
>              argument types are: (str2<int>)
>      func<str2<int> > (s2);

Your code is now accepted, and is being put through some regressions.

-------
Comeau C/C++ 4.3.0.1: FULL CORE LANGUAGE, INCLUDING TC1
Comeau C/C++ ONLINE ==>  http://www.comeaucomputing.com/tryitout
World Class Compilers:  Breathtaking C++, Amazing C99, Fabulous C90.
Comeau C/C++ with Dinkumware's Libraries.  Have you tried it?
comeau@comeaucomputing.com    http://www.comeaucomputing.com
==============================================================

Regards,

Kresimir Fresl


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: deepblue57x@yahoo.co.nz (Graeme Prentice)
Date: Thu, 2 Oct 2003 22:14:17 +0000 (UTC)
Raw View
On Tue, 30 Sep 2003 17:45:45 +0000 (UTC), Patrick.Kowalzick@cern.ch
("Patrick Kowalzick") wrote:

>Here I do not agree. Part 2 says:
>
>Given two overloaded function templates, wheter one is more specialized than
>another can be determined by transforming each template in turn and using
>argument deduction (14.8.2) to compare it to each other.
>
>1. foo() is not overloaded
>2. foo<U> is overloaded
>3. foo<U1,U2> is not overloaded.
>
>So I would use only case 2 which results in same specializaion level. So the
>code could not be compiled.
>

Your comments make no sense so it's difficult to respond to them.

In the original code posted, there are two definitions of the template
function foo, both with a non-empty template parameter list.  Two
template functions with the same name and both with a non empty template
parameter list are overloads of each other.

Case 2 above where you state ... "foo<U> is overloaded" is a nonsense
statement.  foo<U> is a template id.  There is no such thing as an
overloaded template id.  The template function referred to by foo<U> is
overloaded and so is the template function referred to by foo<U1,U2>.

Can you be any clearer about what you're trying to say?

Graeme

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: deepblue57x@yahoo.co.nz (Graeme Prentice)
Date: Thu, 2 Oct 2003 22:14:59 +0000 (UTC)
Raw View
On Wed, 1 Oct 2003 15:53:53 +0000 (UTC), Patrick.Kowalzick@cern.ch
("Patrick Kowalzick") wrote:

>Hello Graeme,
>
>I think I did not express me correct , yesterday. Sorry for that. I do n=
ot
>doubt your explanation of the standard, but I have some problems
>understanding it.

ok, I didn't understand your previous post.

[snip]

>
>OK, I agree but I try to construct a new example, where the first foo
>accepts only a special type. (without any interpretation: bcc32 and g++ =
do
>not compile, MSCV does)

You could also try http://www.comeaucomputing.com/tryitout/
where the Comeau 4.3.3 beta version can be used to compile code snippets
online for free.  (or you can buy the compiler for U.S. $50)


>
>// ***** CODE starts *****
>#include <iostream>
>
>class arg_1 {};
>class arg_2 {};
>
>template<typename A> void foo(const arg_1&)
>{
>   std::cout << "foo<A>" << std::endl;
>}
>
>template<typename R, typename A > void foo(const A&)
>{
>   std::cout << "foo<R, A>" << std::endl;
>}
>
>
>int main() {
>
> foo < arg_1 > ( arg_1() );
> foo < arg_2 > ( arg_2() );
> foo < arg_1 > ( arg_2() );
> foo < arg_2 > ( arg_1() );
>
> foo< arg_1 , arg_1 > ( arg_1() );
> foo< arg_2 , arg_1 > ( arg_1() );
>
>}
>
>// ***** CODE ends *****
>
>Now I try to follow the logic to determine the specialization: -first fo=
o()
>is taking U, calls second with foo(U) which fails because there is no
>possibility to deduct the second type.=20

Close but not quite right  - the partial ordering process says that you
synthesize a set of unique types (or values, or templates) for the
template parameters and substitute them into the function parameters  -
so for the first foo, synthesize a type U for parameter A and substitute
into the function parameter (const arg_1&)  -  since A doesn't appear in
the function parameter anywhere, you are left with const arg_1& as the
type of the argument used to make the call to the second foo().
Deduction then fails because the type of the template parameter R in the
second foo cannot be deduced as you say.



> -second foo() is taking U, calls
>first with foo(U) which fails because arg_1 is expected.

That's close too  - but type of the argument in the call is const U& and
deduction fails as you say because arg_1 is expected.

>
>This means, neither first nor second foo is more specialized and the cal=
l
>foo<U>(arg_1()) may not work.
>(I hope I am right until here otherwise do not read the rest ;-) , which
>means g++ and bcc32 are perfectly right as well)

That's correct.


>
>But me personally would assume the same rules for overloading like the o=
nes
>for not templated functions and just take the first one, because arg_1 i=
s
>the parameter which is passed.

Yes, if you didn't know the intricate rules, that would be the intuitive
choice.


>I found this in
>"14.8.3 Overload Resolution
>[snip]
>The complete set of candidate functions includes all the function templa=
tes
>instantiated in this way ann all of the non-template overload functions =
of
>the same name. The function template specializations are treated like an=
y
>other functions in the remainder of overload resolution,..."

Yes, you also need to look at 13.3.3 para 1 for overload resolution.

[snip]


>Here I mean:
>I do not understand why to compare the calls foo(U) if the calls foo<U>(=
U)
>are causing troubles. Would it be more clear if it is
>"Giving two overloaded function template SPECIALIZATIONS...."
>? In the sense of
>"14.8
>Aa function instantiated from a function template is called a function
>template specialization;"

Yes - it's usually  just called a "specialisation".

The book "C++ Templates The Complete Guide" by Vandevoord and Josuttis
devote a whole appendix to this topic (overload resolution).

To understand what I write (and quote) below, you need to understand
some terminology.

This is a (primary) "function template"
template <typename A>
void foo( const A& )  {  // ...
}

This is an explicit specialisation
template <>
void foo( const int& ) { // ...
}

If I call the function foo like this ... foo( arg_1() )   then the
compiler generates a "specialisation" of the "function template" with
arg_1 as A.

Note how I emphasize the term "function template".  The term "primary"
is also used in relation to templates  - a "function template" is also a
primary template.  In the class of class templates, the term primary is
used to distinguish between class partial specialisation templates
(which are not primary templates) and the class template that it
specialises.  In the case of function templates, there is no partial
specialisation so a function template is always a primary function
template (currently).  An explicit specialization is NOT a function
template.


Now back to overload resolution.

Here's a quote from 13.3.3 (with some of the TC1 corrections applied)


< quote C++ std 13.3.3 para 1, bullets 3,4,5>

Given these definitions, a viable function F1 is defined to be a better
function than another viable function F2 if for all arguments i,
ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then=20

=97 for some argument j, ICSj(F1) is a better conversion sequence than
ICSj(F2), or, if not that,=20

=97 F1 is a nontemplate function and F2 is a function template
specialization, or, if not that,=20

=97 F1 and F2 are function template specializations, and the function
template for F1 is more specialized than the template for F2 according
to the partial ordering rules described in 14.5.5.2, or, if not that,

<end quote>


Overload resolution works roughly like this ...

1. First an overload set is formed by finding all "visible" functions
that match the function name.  This includes function templates but does
NOT include explicit specializations of function templates.

2.  A set of viable functions is formed (13.3.2)  -  functions are
eliminated from the overload set if they have the wrong number of
parameters or if argument deduction fails in the case of a function
template, or if there is no possible conversion sequence in the case of
non-matching argument/parameter types.

3.  The best viable function is then chosen  - this is where the stuff
from 13.3.3 that I quote above, comes in.  In the case of two function
templates, the first thing that happens is that the specialisations
generated from the two templates are compared and if one specialisation
is a "better conversion sequence", then that is the preferred function.
If neither function is a better conversion sequence, the partial
ordering rules (14.5.5.2) are then applied to try and choose.

If one of the two function templates is "more specialised" according to
the partial ordering rules, then that template is used. =20

However, NOTE - having chosen a function template, only then does the
compiler consider explicit specializations of the function template and
may select an explicit specialization if it exactly matches the argument
types in the call.

There is a further twist regarding explicit specialisations  -  an
explicit specialisation can appear to "match" two or more primary
function templates  i.e. it can be "generated" from more than one
function template.  The partial ordering rules are used to decide which
function template matches the explicit specialisation.


Finally, one other little detail to note is that when argument deduction
is done, not all parameters necessarily participate in argument
deduction and for parameters which don't participate in the deduction
(i.e. in the function being called, no deduction occurs for that
parameter), then implicit conversion sequences are allowed  - but for
parameters which participate in deduction, only very limited implicit
conversions are allowed (see 14.8.2.1 para 3).


You can find some more detail on how overload resolution works with
template functions here
http://www.gotw.ca/publications/mill17.htm


Graeme

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gp1@paradise.net.nz (Graeme Prentice)
Date: Mon, 29 Sep 2003 17:03:23 +0000 (UTC)
Raw View
On Wed, 24 Sep 2003 15:23:13 +0000 (UTC), jhrwalter@yahoo.com (Joerg
Walter) wrote:

>
>We're not talking about partial specializations but about the interference
>of explicit specification with argument deduction as far as I understand
>14.1.8 bullet 2:
>
>----------
>Trailing template arguments that can be deduced (14.8.2) may be omitted from
>the list of explicit template-arguments. ...
>----------

This rule means both functions are callable.  The two functions are
overloads of each other.  The compiler uses the partial ordering rules
to determine if one function is more specialised than the other
14.5.5.2 para 1 to 5

Partial ordering applied to these two functions works like this ...

template<typename A>
result<A, typename A::value_type> foo(A const& a) {
   std::cout << "foo<A>" << std::endl;
   return result<A, typename A::value_type>();
}

template<typename R, typename A>
R foo(A const& a) {
   std::cout << "foo<R, A>" << std::endl;
   return R();
}


For the first foo(), synthesize a unique type U for the template type
parameter A and call the second foo  i.e. the call is foo( abc ) where
abc is U const &.  For this call, the compiler is unable to deduce the
type of the template parameter R so deduction fails.

Now this is done in reverse  - for the second foo(), synthesize unique
types U1, U2 for R and A and call the first foo()  - the call is
foo(abc) where abc has type U1 const &.  Deduction succeeds because the
template parameter A of the first function is deduced as U1.  Hence the
second foo is more specialised than the first (para 4 & 5)  so the call
foo<arg2<int> >(s2); is not ambiguous.


Note that when you specify something like foo2<a,b>, there is a rule
14.8.2 para 2 that says  ...
<quote>
The specified template arguments must match the template parameters in
kind (i.e., type, nontype, template),and there must not be more
arguments than there are parameters; otherwise type deduction fails.
<>

Hence for the call foo2<a,b> the compiler is forced to call a function
that has at least two template parameters.  It cannot call a non
template function and it cannot call a template function with one
parameter, but it can call a template function with two *or more*
template parameters if additional trailing parameters can be deduced.

Graeme

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: jhrwalter@yahoo.com (Joerg Walter)
Date: Mon, 29 Sep 2003 17:09:45 +0000 (UTC)
Raw View
Kresimir Fresl wrote:

> I wrote:
>
> > Joerg Walter wrote:
>
> >> I've already tried to discuss the following two programs on
> >> comp.lang.c++.moderated. Kresimir Fresl's test case
> [...]
> >> is accepted by GCC 3.3.1, a program run results in
> [...]
> >> ICC 7.1 and MSVC 7.1 reject this code.
>
> > And Comeau C/C++ 4.3.0.1, too.
> >
> > Some time ago (in January) I asked Comeau's support team about
> > it. Here is their reply:
> > ================================================================
> > [...] We suspect your case
> > is ill-formed but still need to go through that Standard more
> > thoroughly on it before saying so for certain, and we also want
> > to double check it is not impacted by any pending defect report.
> > ================================================================
> >
> > But they never said `so for certain', and, if `so', why.
>
> Yesterday I received the following mail from Comeau Computing:
> ================================================================
> ================================================================
> At 10:39 AM 1/14/2003 +0100, Kresimir Fresl wrote:
>
> > Following program cannot be compiled with
> > Comeau C/C++ 4.3.0.1:
> >
> > ==========================================
> > template <typename A, typename T>
> > struct result {};
> >
> > template <typename A>
> > result<A, typename A::val_t> func (A const& a) {
> >    return result<A, typename A::val_t>();
> > }
> > template <typename R, typename A>
> > R func (A const& a) {
> >    return R();
> > }
> >
> > template <typename T>
> > struct str1 {
> >    typedef T val_t;
> > };
> > template <typename T>
> > struct str2 {
> >    typedef T val_t;
> > };
> >
> > int main() {
> >    str1<int> s1;
> >    str2<int> s2;
> >
> >    func (s1);    // OK
> >    func (s2);    // OK
> >
> >    func<str1<int> > (s1);   // error1
> >    func<str2<int> > (s1);   // OK
> >    func<str1<int> > (s2);   // OK
> >    func<str2<int> > (s2);   // error2
> > }
> > ==========================================
> > error1: more than one instance of overloaded
> >            function "func" matches the argument list:
> >              function template "func(const A &)"
> >              function template "func<R,A>(const A &)"
> >              argument types are: (str1<int>)
> >      func<str1<int> > (s1);
> > error2: more than one instance of overloaded
> >            function "func" matches the argument list:
> >              function template "func(const A &)"
> >              function template "func<R,A>(const A &)"
> >              argument types are: (str2<int>)
> >      func<str2<int> > (s2);
>
> Your code is now accepted, and is being put through some regressions.

Surprising: it seems some people at Comeau and EDG are convinced now
that the test case is legal C++.

I still have no indication to decide that question for me. So I'll
have to retreat and study the standard (for a couple of years?).

Regards,
Joerg

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Patrick.Kowalzick@cern.ch ("Patrick Kowalzick")
Date: Tue, 30 Sep 2003 17:45:45 +0000 (UTC)
Raw View
Hello all,

> This rule means both functions are callable.  The two functions are
> overloads of each other.  The compiler uses the partial ordering rules
> to determine if one function is more specialised than the other
> 14.5.5.2 para 1 to 5

I completely agree. Here we should read.

> Partial ordering applied to these two functions works like this ...
>
> template<typename A>
> result<A, typename A::value_type> foo(A const& a) {
>    std::cout << "foo<A>" << std::endl;
>    return result<A, typename A::value_type>();
> }
>
> template<typename R, typename A>
> R foo(A const& a) {
>    std::cout << "foo<R, A>" << std::endl;
>    return R();
> }
>
>
> For the first foo(), synthesize a unique type U for the template type
> parameter A and call the second foo  i.e. the call is foo( abc ) where
> abc is U const &.  For this call, the compiler is unable to deduce the
> type of the template parameter R so deduction fails.
>
> Now this is done in reverse  - for the second foo(), synthesize unique
> types U1, U2 for R and A and call the first foo()  - the call is
> foo(abc) where abc has type U1 const &.  Deduction succeeds because the
> template parameter A of the first function is deduced as U1.  Hence the
> second foo is more specialised than the first (para 4 & 5)  so the call
> foo<arg2<int> >(s2); is not ambiguous.

Here I do not agree. Part 2 says:

Given two overloaded function templates, wheter one is more specialized than
another can be determined by transforming each template in turn and using
argument deduction (14.8.2) to compare it to each other.

1. foo() is not overloaded
2. foo<U> is overloaded
3. foo<U1,U2> is not overloaded.

So I would use only case 2 which results in same specializaion level. So the
code could not be compiled.

Regards,
Patrick


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: jhrwalter@yahoo.com (Joerg Walter)
Date: Wed, 1 Oct 2003 05:50:43 +0000 (UTC)
Raw View
gp1@paradise.net.nz (Graeme Prentice) wrote in message news:<fur9nvsta83c5et8drf2amoqhhs1lvoqu5@4ax.com>...
> On Wed, 24 Sep 2003 15:23:13 +0000 (UTC), jhrwalter@yahoo.com (Joerg
> Walter) wrote:
>
> >
> >We're not talking about partial specializations but about the interference
> >of explicit specification with argument deduction as far as I understand
> >14.1.8 bullet 2:
> >
> >----------
> >Trailing template arguments that can be deduced (14.8.2) may be omitted from
> >the list of explicit template-arguments. ...
> >----------
>
> This rule means both functions are callable.  The two functions are
> overloads of each other.  The compiler uses the partial ordering rules
> to determine if one function is more specialised than the other
> 14.5.5.2 para 1 to 5

OK.

> Partial ordering applied to these two functions works like this ...
>
> template<typename A>
> result<A, typename A::value_type> foo(A const& a) {
>    std::cout << "foo<A>" << std::endl;
>    return result<A, typename A::value_type>();
> }
>
> template<typename R, typename A>
> R foo(A const& a) {
>    std::cout << "foo<R, A>" << std::endl;
>    return R();
> }
>
>
> For the first foo(), synthesize a unique type U for the template type
> parameter A and call the second foo  i.e. the call is foo( abc ) where
> abc is U const &.  For this call, the compiler is unable to deduce the
> type of the template parameter R so deduction fails.

I see.

> Now this is done in reverse  - for the second foo(), synthesize unique
> types U1, U2 for R and A and call the first foo()  - the call is
> foo(abc) where abc has type U1 const &.  Deduction succeeds because the
> template parameter A of the first function is deduced as U1.  Hence the
> second foo is more specialised than the first (para 4 & 5)  so the call
> foo<arg2<int> >(s2); is not ambiguous.

I see, too.

[...]

Thanks a lot for your explanation,
Joerg

P.S.: but this resolution is still surprising ;-)

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Patrick.Kowalzick@cern.ch ("Patrick Kowalzick")
Date: Wed, 1 Oct 2003 15:53:53 +0000 (UTC)
Raw View
Hello Graeme,

I think I did not express me correct , yesterday. Sorry for that. I do not
doubt your explanation of the standard, but I have some problems
understanding it.

My aim here is to understand the behaviour of code. But our example here is
a very tough one, and I bet if you ask very experienced programmers you get
a bunch of diferent answers.

This is a reason why I "do not like" your answer, even if I could follow. If
I knew how to determine which function is called with a call, I would need
several hours to get the clue for a 20 lines program. And afterwards I would
not be sure if I did it correct.

> > Partial ordering applied to these two functions works like this ...
> >
> > template<typename A>
> > result<A, typename A::value_type> foo(A const& a) {
> >    std::cout << "foo<A>" << std::endl;
> >    return result<A, typename A::value_type>();
> > }
> >
> > template<typename R, typename A>
> > R foo(A const& a) {
> >    std::cout << "foo<R, A>" << std::endl;
> >    return R();
> > }
> >
> >
> > For the first foo(), synthesize a unique type U for the template
> > type parameter A and call the second foo  i.e. the call is foo( abc
> > ) where abc is U const &.  For this call, the compiler is unable to
> > deduce the type of the template parameter R so deduction fails.
> >
> > Now this is done in reverse  - for the second foo(), synthesize
> > unique types U1, U2 for R and A and call the first foo()  - the call
> > is
> > foo(abc) where abc has type U1 const &.  Deduction succeeds because the
> > template parameter A of the first function is deduced as U1.  Hence the
> > second foo is more specialised than the first (para 4 & 5)  so the call
> > foo<arg2<int> >(s2); is not ambiguous.

OK, I agree but I try to construct a new example, where the first foo
accepts only a special type. (without any interpretation: bcc32 and g++ do
not compile, MSCV does)

// ***** CODE starts *****
#include <iostream>

class arg_1 {};
class arg_2 {};

template<typename A> void foo(const arg_1&)
{
   std::cout << "foo<A>" << std::endl;
}

template<typename R, typename A > void foo(const A&)
{
   std::cout << "foo<R, A>" << std::endl;
}


int main() {

 foo < arg_1 > ( arg_1() );
 foo < arg_2 > ( arg_2() );
 foo < arg_1 > ( arg_2() );
 foo < arg_2 > ( arg_1() );

 foo< arg_1 , arg_1 > ( arg_1() );
 foo< arg_2 , arg_1 > ( arg_1() );

}

// ***** CODE ends *****

Now I try to follow the logic to determine the specialization: -first foo()
is taking U, calls second with foo(U) which fails because there is no
possibility to deduct the second type. -second foo() is taking U, calls
first with foo(U) which fails because arg_1 is expected.

This means, neither first nor second foo is more specialized and the call
foo<U>(arg_1()) may not work.
(I hope I am right until here otherwise do not read the rest ;-) , which
means g++ and bcc32 are perfectly right as well)

But me personally would assume the same rules for overloading like the ones
for not templated functions and just take the first one, because arg_1 is
the parameter which is passed.
I found this in
"14.8.3 Overload Resolution
[snip]
The complete set of candidate functions includes all the function templates
instantiated in this way ann all of the non-template overload functions of
the same name. The function template specializations are treated like any
other functions in the remainder of overload resolution,..."

I personally would assume a call to the first foo() for each call
foo<U>(arg_1()); with the definition of the overload resolution.
(which MSVC does) and for the second with foo<U>(arg_2()); which is
absolutly clear.
Anyway I am really confused with all the different expressions used and I am
sure I mixed them all up.

> Here I do not agree. Part 2 says:
>
> Given two overloaded function templates, wheter one is more
> specialized than another can be determined by transforming each
> template in turn and using argument deduction (14.8.2) to compare it
> to each other.
>
> 1. foo() is not overloaded
> 2. foo<U> is overloaded
> 3. foo<U1,U2> is not overloaded.
>
> So I would use only case 2 which results in same specializaion level.
> So the code could not be compiled.

Here I mean:
I do not understand why to compare the calls foo(U) if the calls foo<U>(U)
are causing troubles. Would it be more clear if it is
"Giving two overloaded function template SPECIALIZATIONS...."
? In the sense of
"14.8
Aa function instantiated from a function template is called a function
template specialization;"
Or is this completly misinterpreted?

I am really confused, could not follow the logic and decided myself to keep
the fingers away from constructions like that ;-).

Thanks a lot for your time,
Patrick


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: jhrwalter@yahoo.com (Joerg Walter)
Date: Sat, 20 Sep 2003 16:49:05 +0000 (UTC)
Raw View
Hello,

I've already tried to discuss the following two programs on
comp.lang.c++.moderated. Kresimir Fresl's test case

----------
#include <iostream>

template<typename A, typename T>
struct result {};

template<typename T>
struct arg1 {
   typedef T value_type;
};
template<typename T>
struct arg2 {
   typedef T value_type;
};

template<typename A>
result<A, typename A::value_type> foo(A const& a) {
   std::cout << "foo<A>" << std::endl;
   return result<A, typename A::value_type>();
}
template<typename R, typename A>
R foo(A const& a) {
   std::cout << "foo<R, A>" << std::endl;
   return R();
}

int main() {
   arg1<int> s1;
   arg2<int> s2;

   foo(s2);    // OK

   foo<arg1<int>, arg2<int> >(s2);  // OK
   foo<arg2<int>, arg2<int> >(s2);  // OK

   foo<arg1<int> >(s2);    // OK
   foo<arg2<int> >(s2);    // Ambigous?
}

----------

is accepted by GCC 3.3.1, a program run results in

foo<A>
foo<R, A>
foo<R, A>
foo<R, A>
foo<R, A>

ICC 7.1 and MSVC 7.1 reject this code. Patrick Kowalzick's reduced
test case

----------
#include <iostream>

// no basic types to avoid automatic casting
class arg_1 {};
class arg_2 {};

template<typename A> void foo(A const& a)
{
   std::cout << "foo<A>" << std::endl;
}

template<typename R, typename A> void foo(A const& a)
{
   std::cout << "foo<R, A>" << std::endl;
}

int main() {

 foo ( arg_1() );

 foo < arg_1 > ( arg_1() );  // Ambigous?
 foo < arg_2 > ( arg_1() );  // OK

 foo< arg_1 , arg_1 > ( arg_1() );  // OK
 // foo< arg_1 , arg_2 > ( arg_1() );  // no casting from 1 to 2
 foo< arg_2 , arg_1 > ( arg_1() );  // OK
 // foo< arg_2 , arg_2 > ( arg_1() );  // no casting from 1 to 2

}

----------

is accepted by GCC 3.3.1 and ICC 7.1. MSVC 7.1 rejects that code.

Are these legal C++ programs?

Thanks for any enlightenment,
Joerg Walter

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: fresl@grad.hr (Kresimir Fresl)
Date: Mon, 22 Sep 2003 17:05:00 +0000 (UTC)
Raw View
Joerg Walter wrote:

> I've already tried to discuss the following two programs on
> comp.lang.c++.moderated. Kresimir Fresl's test case
>
> ----------
> #include <iostream>
>
> template<typename A, typename T>
> struct result {};
>
> template<typename T>
> struct arg1 {
>    typedef T value_type;
> };
> template<typename T>
> struct arg2 {
>    typedef T value_type;
> };
>
> template<typename A>
> result<A, typename A::value_type> foo(A const& a) {
>    std::cout << "foo<A>" << std::endl;
>    return result<A, typename A::value_type>();
> }
> template<typename R, typename A>
> R foo(A const& a) {
>    std::cout << "foo<R, A>" << std::endl;
>    return R();
> }
>
> int main() {
>    arg1<int> s1;
>    arg2<int> s2;
>
>    foo(s2);    // OK
>
>    foo<arg1<int>, arg2<int> >(s2);  // OK
>    foo<arg2<int>, arg2<int> >(s2);  // OK
>
>    foo<arg1<int> >(s2);    // OK
>    foo<arg2<int> >(s2);    // Ambigous?
> }
>
> ----------
>
> is accepted by GCC 3.3.1, a program run results in
>
> foo<A>
> foo<R, A>
> foo<R, A>
> foo<R, A>
> foo<R, A>
>
> ICC 7.1 and MSVC 7.1 reject this code.

And Comeau C/C++ 4.3.0.1, too.

Some time ago (in January) I asked Comeau's support team about
it. Here is their reply:
================================================================
[...] We suspect your case
is ill-formed but still need to go through that Standard more
thoroughly on it before saying so for certain, and we also want
to double check it is not impacted by any pending defect report.
================================================================

But they never said `so for certain', and, if `so', why.

Regards,

Kresimir Fresl


PS. I also tried 4.3.3 beta online:

    http://www.comeaucomputing.com/tryitout/

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Christian.Theis@nospam.cern.ch ("Chris Theis")
Date: Tue, 23 Sep 2003 18:54:23 +0000 (UTC)
Raw View
"Kresimir Fresl" <fresl@grad.hr> wrote in message
news:3F6E975F.8050300@grad.hr...
>
> Joerg Walter wrote:
>
> > I've already tried to discuss the following two programs on
> > comp.lang.c++.moderated. Kresimir Fresl's test case
> >
> > ----------
> > #include <iostream>
> >
> > template<typename A, typename T>
> > struct result {};
> >
> > template<typename T>
> > struct arg1 {
> >    typedef T value_type;
> > };
> > template<typename T>
> > struct arg2 {
> >    typedef T value_type;
> > };
> >
> > template<typename A>
> > result<A, typename A::value_type> foo(A const& a) {
> >    std::cout << "foo<A>" << std::endl;
> >    return result<A, typename A::value_type>();
> > }
> > template<typename R, typename A>
> > R foo(A const& a) {
> >    std::cout << "foo<R, A>" << std::endl;
> >    return R();
> > }
> >
> > int main() {
> >    arg1<int> s1;
> >    arg2<int> s2;
> >
> >    foo(s2);    // OK
> >
> >    foo<arg1<int>, arg2<int> >(s2);  // OK
> >    foo<arg2<int>, arg2<int> >(s2);  // OK
> >
> >    foo<arg1<int> >(s2);    // OK
> >    foo<arg2<int> >(s2);    // Ambigous?
> > }
> >
> > ----------
> >
> > is accepted by GCC 3.3.1, a program run results in
> >
> > foo<A>
> > foo<R, A>
> > foo<R, A>
> > foo<R, A>
> > foo<R, A>
> >
> > ICC 7.1 and MSVC 7.1 reject this code.
>
> And Comeau C/C++ 4.3.0.1, too.
>
> Some time ago (in January) I asked Comeau's support team about
> it. Here is their reply:
> ================================================================
> [...] We suspect your case
> is ill-formed but still need to go through that Standard more
> thoroughly on it before saying so for certain, and we also want
> to double check it is not impacted by any pending defect report.
> ================================================================
>
> But they never said `so for certain', and, if `so', why.
>
> Regards,
>
> Kresimir Fresl
>
>
> PS. I also tried 4.3.3 beta online:
>
>     http://www.comeaucomputing.com/tryitout/
>

According to the Standard (chapter about type deduction for partial
specialized templates) there is no such thing as partial specialization for
functions (yet). The closest thing you can get your hands on to is
overloading. Thanks to A. Alexandrescu here is a neat idea which puts this
into action:

template <typename T>
struct CType2Type {
  typedef T OriginalType;
};

template< class T, class U>
T* Create( const U& Argument, CType2Type<T> )
{
  return new T( Argument );
}

template<class U>
CMyObj* Create( const U& Argument, CType2Type<CMyObj>)
{
  return new CMyObj( Argument );
}

CMyOtherObj* = Create( "test", CType2Type<CMyOtherObj>() );     // calling
generic version
CMyObj* = Create( "test", CType2Type<CMyObj>() );                      //
calling "specialized" version


The honor of this idea & example go to Andrei, a real template guru!

HTH
Chris


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]