Prev: It would be better if unique_ptr were a type modifier?
Next: Is there any standard/guarantees for exception safety in STL operations?
From: Rodolfo Lima on 25 Jul 2010 00:18 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 25 Jul 2010 08:56 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 25 Jul 2010 23:07 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 25 Jul 2010 23:13 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 26 Jul 2010 02:48
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! ] |