From: Kirill_Lykov on
On Jul 26, 6:56 am, 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
>
> HTH & Greetings from Bremen,
>
> Daniel Krügler
>

Сould answer one more question about this code?
This code with some changes* may be compiled with VS 2010, but If I
change the default type in the enable_if from void to int, it will
cause a error:
"use of undefined type 'foo<T,ID>' with [ T=bar<int>, ID=1 ]"

However the code below works as I expect (according with 14.2.10).

template <bool B, class V = int>
struct enable_if
{
};

template <class V>
struct enable_if<true, V>
{
typedef V type;
};

auto v = enable_if<8!=0>(); // V == int

* to make it work I changed the second template foo specialization
this way:

template<class T, int ID, template<class> class V>
struct foo<T, ID, V<T>> ...


--
[ 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 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.
>

Indeed, I think the problem that guy describes in that issue report is
similar to the problem we have here. I've analyzed the first case of the
issue report, and i come to the same conclusion as comeau: The code seems to
be valid:

void(T, typename A<T>::type) // T1
void(T*, typename A<T>::type*) // T2

void(Tx, A<Tx>::type) // XT1
void(Tx*, A<Tx>::type*) // XT2


XT1 -> T2

void(Tx, A<Tx>::type)
void(T*, typename A<T>::type*)

=> T* does not match Tx, second param non-deduced context


XT2 -> T1

void(Tx*, A<Tx>::type*)
void(T, typename A<T>::type)

=> T = Tx*, second param non-deduced context

XT2 -> T1 OK, T2 at least as specialized as T1
XT1 -> T2 FAIL

=> T2 more specialized than T1.


Clang and GCC don't seem to do partial ordering in the first place, i think.
There is a difference between these two sets of compiler behaviors with
regard to handling non-deduced contexts during argument deduction itself - i
don't believe the difference is due to partial ordering. I have done two
examples:

template<typename T>
struct id { typedef T *type; };

template<typename T>
void f(T, typename id<T>::type);

int main() { f(0, 0); }

And

template<typename T>
struct id { typedef T type; };

template<typename T>
void f(T, typename id<T>::type*);

int main() { f(0, 0); }

The only difference is the placement of the star. Comeau accepts both
examples, because in both cases "int" is not compared to the non-deduced
context, which i think is the correct behavior. GCC and Clang however only
accept the first, for reasons unknown to me. They seem to think that a
pointer cannot possibly match an int and reject, maybe thinking that this
"dependent-type *" is a compound type, and they are allowed to do so
(paragraph 6). I don't think that's correct though. The allowance of the
Standard for compound types to contain both deduced and non-deduced contexts
does not seem to apply to a ptr-declarator being still allowed to be checked
- the phrase "compound types" seems to refer to the list in
14.9.2.5[temp.deduct.type]/3 - not to the general one in 3[basic] (and then
interpreting a star piece as a "type" is still quite a stretch).

There are two cases that i know of that can prevent comparison:

- An argument that contains only explicitly specified arguments/contains no
deduced arguments (14.9.1[temp.arg.explicit]/6)
- Nondeduced context (14.9.2.5[temp.deduct.type]/4)

The first is handled consistently also by Clang and GCC:

template<typename T> void f(T);
int main() { f<int*>(0); }


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