From: Rodolfo Lima on
Hi, I'm having some problems with the following code, gcc-4.5 refuses
to compile it:

#include <iostream>

template <bool B, class V=void> struct enable_if {};
template <class V> struct enable_if<true,V> { typedef V type; };

template <class T>
struct bar {};

template <class T, int ID, class V=void>
struct foo;

template<template<class> class V, class T, int ID>
struct foo<V<T>, ID>
{
static const int value = 1;

};

template<class T, int ID>
struct foo<bar<T>,ID, typename enable_if<ID!=0>::type>
{
static const int value = 2;

};

int main()
{
std::cout << foo<bar<int>,1>::value << std::endl;

}

//------------------------------------------

The error message:
teste.cpp: In function �int main()�:
teste.cpp:26:30: error: ambiguous class template instantiation for
�struct foo<bar<int>, 1>�
teste.cpp:14:1: error: candidates are: struct foo<V<T>, ID>
teste.cpp:20:1: error: struct foo<bar<T>, ID, typename
enable_if<(ID != 0)>::type>
teste.cpp:26:15: error: incomplete type �foo<bar<int>, 1>� used in
nested name specifier

According to partial ordering rules, struct foo<bar<T>,ID, typename
enable_if<ID!=0>::type> is more specialized than struct foo<V<T>, ID>,
isn't it? So it should be used, instead of giving an ambiguity error.

Am I wrong or is the compiler?

Regards,
Rodolfo Lima


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Daniel Krügler on
On 25 Jul., 17:18, Rodolfo Lima <rodo...(a)rodsoft.org> wrote:
> Hi, I'm having some problems with the following code, gcc-4.5 refuses
> to compile it:
>
> #include <iostream>
>
> template <bool B, class V=void> struct enable_if {};
> template <class V> struct enable_if<true,V> { typedef V type; };
>
> template <class T>
> struct bar {};
>
> template <class T, int ID, class V=void>
> struct foo;
>
> template<template<class> class V, class T, int ID>
> struct foo<V<T>, ID>
> {
> static const int value = 1;
> };
>
> template<class T, int ID>
> struct foo<bar<T>,ID, typename enable_if<ID!=0>::type>
> {
> static const int value = 2;
> };
>
> int main()
> {
> std::cout << foo<bar<int>,1>::value << std::endl;
> }
>
> //------------------------------------------
>
> The error message:
> teste.cpp: In function �int main()�:
> teste.cpp:26:30: error: ambiguous class template instantiation for
> �struct foo<bar<int>, 1>�
> teste.cpp:14:1: error: candidates are: struct foo<V<T>, ID>
> teste.cpp:20:1: error: struct foo<bar<T>, ID, typename
> enable_if<(ID != 0)>::type>
> teste.cpp:26:15: error: incomplete type �foo<bar<int>, 1>� used in
> nested name specifier
>
> According to partial ordering rules, struct foo<bar<T>,ID, typename
> enable_if<ID!=0>::type> is more specialized than struct foo<V<T>, ID>,
> isn't it? So it should be used, instead of giving an ambiguity error.
>
> Am I wrong or is the compiler?

This time it's you ;-)

The problem is that in the attempt to define the partial
specialization

template<class T, int ID>
struct foo<bar<T>,ID, typename enable_if<ID!=0>::type>;

you are running into a non-deducible context for the last
argument. Unfortunately the standard does not require this
attempt to be ill-formed. There is a core issue concerning
this situation, see:

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#549

HTH & Greetings from Bremen,

Daniel Kr�gler


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Johannes Schaub (litb) on
Daniel Krügler wrote:

> On 25 Jul., 17:18, Rodolfo Lima <rodo...(a)rodsoft.org> wrote:
>> Hi, I'm having some problems with the following code, gcc-4.5 refuses
>> to compile it:
>>
>> #include <iostream>
>>
>> template <bool B, class V=void> struct enable_if {};
>> template <class V> struct enable_if<true,V> { typedef V type; };
>>
>> template <class T>
>> struct bar {};
>>
>> template <class T, int ID, class V=void>
>> struct foo;
>>
>> template<template<class> class V, class T, int ID>
>> struct foo<V<T>, ID>
>> {
>> static const int value = 1;
>> };
>>
>> template<class T, int ID>
>> struct foo<bar<T>,ID, typename enable_if<ID!=0>::type>
>> {
>> static const int value = 2;
>> };
>>
>> int main()
>> {
>> std::cout << foo<bar<int>,1>::value << std::endl;
>> }
>>
>> //------------------------------------------
>>
>> The error message:
>> teste.cpp: In function 'int main()':
>> teste.cpp:26:30: error: ambiguous class template instantiation for
>> 'struct foo<bar<int>, 1>'
>> teste.cpp:14:1: error: candidates are: struct foo<V<T>, ID>
>> teste.cpp:20:1: error: struct foo<bar<T>, ID, typename
>> enable_if<(ID != 0)>::type>
>> teste.cpp:26:15: error: incomplete type 'foo<bar<int>, 1>' used in
>> nested name specifier
>>
>> According to partial ordering rules, struct foo<bar<T>,ID, typename
>> enable_if<ID!=0>::type> is more specialized than struct foo<V<T>, ID>,
>> isn't it? So it should be used, instead of giving an ambiguity error.
>>
>> Am I wrong or is the compiler?
>
> This time it's you ;-)
>
> The problem is that in the attempt to define the partial
> specialization
>
> template<class T, int ID>
> struct foo<bar<T>,ID, typename enable_if<ID!=0>::type>;
>
> you are running into a non-deducible context for the last
> argument. Unfortunately the standard does not require this
> attempt to be ill-formed. There is a core issue concerning
> this situation, see:
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#549
>

The issue report and his partial specializations are two separate things,
though. In this partial specialization, both T and ID are deducible from the
types of the specialization: The partial specialization thus matches. But
the partial specialization in the issue report can never match, thus the
concerns about the validity of the code in it.

I believe that partial ordering is a difficult thing to understand, and in
my opinion the Standard doesn't make it quite easy. I hope this time i get
it right, but i fear i have it all wrong. Let's see :) For the given code, i
think the following will happen:

* Rewrite them to function templates

=>

template<template<class> class V, class T, int ID>
void f(foo<V<T>, ID, void>); // T1

And

template<class T, int ID>
void f(foo<bar<T>, ID, typename enable_if<ID!=0>::type>); // T2

* Invent "unique" types, templates and values for the template parameters

void(foo<Vx<Tx>, IDx, void>); // XT1 (transformed T1)
void(foo<bar<Tx>, IDx, enable_if<IDx != 0>::type>) // XT2

For the function type of the transformed declaration, we keep the third
parameter dependent in case of enable_if, and apply the "equivalence" rule
according to 14.6.6.1 to compare its type identity. Now, we deduce XT1
against T2 and XT2 against T1. If both deductions fail or both succeed,
there is no partial order:

XT1 against T2 is:

foo<Vx <Tx>, IDx, void>
foo<bar<T >, ID, enable_if<ID!=0>::type> // T and ID

ID could be deduced to IDx, but "bar" does not match "Vx". The third part is
not compared to "void" because it's a non-deduced context.

XT2 against T1 is:

foo<bar<Tx>, IDx, enable_if<IDx != 0>::type>
foo<V <T >, ID, void> // V, T and ID

We deduce V to bar, T to Tx, but we are not able to match "void" (which is
not a non-deduced context) to "enable_if<...>::type".

Both deduction runs fail, so we have no order.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Daniel Krügler on
On 26 Jul., 01:56, Daniel Kr�gler <daniel.krueg...(a)googlemail.com>
wrote:
> On 25 Jul., 17:18, Rodolfo Lima <rodo...(a)rodsoft.org> wrote:
>
>
>
> > Hi, I'm having some problems with the following code, gcc-4.5 refuses
> > to compile it:
>
> > #include <iostream>
>
> > template <bool B, class V=void> struct enable_if {};
> > template <class V> struct enable_if<true,V> { typedef V type; };
>
> > template <class T>
> > struct bar {};
>
> > template <class T, int ID, class V=void>
> > struct foo;
>
> > template<template<class> class V, class T, int ID>
> > struct foo<V<T>, ID>
> > {
> > static const int value = 1;
> > };
>
> > template<class T, int ID>
> > struct foo<bar<T>,ID, typename enable_if<ID!=0>::type>
> > {
> > static const int value = 2;
> > };
>
> > int main()
> > {
> > std::cout << foo<bar<int>,1>::value << std::endl;
> > }
>
> > //------------------------------------------
>
> > The error message:
> > teste.cpp: In function �int main()�:
> > teste.cpp:26:30: error: ambiguous class template instantiation for
> > �struct foo<bar<int>, 1>�
> > teste.cpp:14:1: error: candidates are: struct foo<V<T>, ID>
> > teste.cpp:20:1: error: struct foo<bar<T>, ID, typename
> > enable_if<(ID != 0)>::type>
> > teste.cpp:26:15: error: incomplete type �foo<bar<int>, 1>� used in
> > nested name specifier
>
> > According to partial ordering rules, struct foo<bar<T>,ID, typename
> > enable_if<ID!=0>::type> is more specialized than struct foo<V<T>, ID>,
> > isn't it? So it should be used, instead of giving an ambiguity error.
>
> > Am I wrong or is the compiler?
>
> This time it's you ;-)
>
> The problem is that in the attempt to define the partial
> specialization
>
> template<class T, int ID>
> struct foo<bar<T>,ID, typename enable_if<ID!=0>::type>;
>
> you are running into a non-deducible context for the last
> argument. Unfortunately the standard does not require this
> attempt to be ill-formed. There is a core issue concerning
> this situation, see:
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#549

I was a bit too quick here: My analysis was wrong, because
ID has already been deduced. So let's declare the two test
overloads to verify partial ordering:

template<template<class> class V, class T, int ID>
void test(foo<V<T>, ID>);

template<class T, int ID>
void test(foo<bar<T>,ID, typename enable_if<ID!=0>::type>);

I agree that the ambiguity is astonishing. I have the feeling you
are running into core issue

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#455

which describes problems with partial ordering in the presence
of non-deduced arguments, but I'm not 100% sure.

HTH & Greetings from Bremen,

Daniel Kr�gler


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Rodolfo Lima on
On Jul 26, 11:07 am, "Johannes Schaub (litb)" <schaub-johan...(a)web.de>
wrote:
> XT2 against T1 is:
>
> foo<bar<Tx>, IDx, enable_if<IDx != 0>::type>
> foo<V <T >, ID, void> // V, T and ID
>
> We deduce V to bar, T to Tx, but we are not able to match "void" (which is
> not a non-deduced context) to "enable_if<...>::type".

Here's what I thought: since all template parameters were deduced from
the first 2 arguments, the compiler would apply the deduced ID into
enable_if<ID!=0>::type, yielding 'void', and voil�, void matches to
void.

The question is: is there any side-effects to treat non-deduced
contexts during partial ordering this way, namely:
1- deduce all template parameters from arguments are in the form that
allows deduction (14.8.2.4.9). If at least one parameter isn't
deduced, well, it's a deduction failure.
2- apply all deduced parameters into arguments that falls into non-
deduced context and evaluate whichever compile-time expressions might
appear
3- use the resulting function signature to verify if there's a match

[]s,
rod



--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]