Prev: Distinguish between pointers created with 'new' and created with references.
Next: templates and default parameters
From: Edward Diener on 15 Jul 2010 10:36 The code below compiles without error, but I think the static_assert should trigger: --------------------------------------------------------------------- struct test_default { }; namespace test_template1 { template < class T1, class P1_1, class P1_2 > char test(typename T1::template AMemberTemplate<P1_1,P1_2> *); template < class T1, class P1_1, class P1_2 > char (&test(...))[2]; } namespace test_template2 { template < class T1, class P1_1 > char test(typename T1::template AMemberTemplate<P1_1> *); template < class T1, class P1_1 > char (&test(...))[2]; } template < class T, class P1 = test_default, class P2 = test_default > struct test_template { typedef test_template type; static const bool value=sizeof(test_template1::test<T,P1,P2>(0)==1); }; template < class T, class P1 > struct test_template < T, P1, test_default > { typedef test_template type; static const bool value=sizeof(test_template2::test<T,P1>(0)==1); }; struct TType { template <class X> struct AMemberTemplate { }; }; static_assert(test_template<TType>::value,"Error"); ----------------------------------------------------------------- Why does not the expression 'test_template<TType>' use the main 'test_template' template rather than the partial specialization ? -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Edward Diener on 16 Jul 2010 01:29 On 7/15/2010 9:36 PM, Edward Diener wrote: > The code below compiles without error, but I think the static_assert > should trigger: > > --------------------------------------------------------------------- > > struct test_default { }; > > namespace test_template1 > { > template > < > class T1, > class P1_1, > class P1_2 > > > char test(typename T1::template AMemberTemplate<P1_1,P1_2> *); > > template > < > class T1, > class P1_1, > class P1_2 > > > char (&test(...))[2]; > } > > namespace test_template2 > { > template > < > class T1, > class P1_1 > > > char test(typename T1::template AMemberTemplate<P1_1> *); > > template > < > class T1, > class P1_1 > > > char (&test(...))[2]; > } > > template > < > class T, > class P1 = test_default, > class P2 = test_default > > > struct test_template > { > typedef test_template type; > > static const bool value=sizeof(test_template1::test<T,P1,P2>(0)==1); > }; > > template > < > class T, > class P1 > > > struct test_template > < > T, > P1, > test_default > > > { > typedef test_template type; > > static const bool value=sizeof(test_template2::test<T,P1>(0)==1); > }; > > struct TType > { > template <class X> struct AMemberTemplate { }; > }; > > static_assert(test_template<TType>::value,"Error"); > > ----------------------------------------------------------------- > > Why does not the expression 'test_template<TType>' use the main > 'test_template' template rather than the partial specialization ? The example is incorrect and should be instead: --------------------------------------------------------------------- struct test_default { }; namespace test_template1 { template < class T1, class P1_1, class P1_2 > char test(typename T1::template AMemberTemplate<P1_1,P1_2> *); template < class T1, class P1_1, class P1_2 > char (&test(...))[2]; } namespace test_template2 { template < class T1, class P1_1 > char test(typename T1::template AMemberTemplate<P1_1> *); template < class T1, class P1_1 > char (&test(...))[2]; } template < class T, class P1 = test_default, class P2 = test_default > struct test_template { typedef test_template type; static const bool value=sizeof(test_template1::test<T,P1,P2>(0))==1; }; template < class T, class P1 > struct test_template < T, P1, test_default > { typedef test_template type; static const bool value=sizeof(test_template2::test<T,P1>(0))==1; }; struct TType { template <class X> struct AMemberTemplate { }; }; static_assert(test_template<TType>::value,"Error"); ----------------------------------------------------------------- I was also answered elsewhere that "the most specialized version of a given template is always chosen". Since both the main template and the specialization matched the 'test_template<TType>' instantiation, the specialization is chosen. -- [ 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 16 Jul 2010 07:33
Edward Diener wrote: > On 7/15/2010 9:36 PM, Edward Diener wrote: >> The code below compiles without error, but I think the static_assert >> should trigger: >> > [ code snipped ] > > ----------------------------------------------------------------- > > I was also answered elsewhere that "the most specialized version of a > given template is always chosen". Since both the main template and the > specialization matched the 'test_template<TType>' instantiation, the > specialization is chosen. > In this case, it's even simplier, i think. For the "comparison" between a primary template and its partial specializations that match, the primary template is never taken, no matter what's up with it. That is, partial ordering for class templates to determine the most specialized template is only done among partial specializations, never with a primary template in the boat. Consider: template<typename T, typename U> struct Foo { }; template<typename T, typename U> struct Foo<U, T> { // reverse of the implicit primary list typedef int type; }; Foo<SomeType, OtherType>::type a; Perfectly valid. But partial specialization rules would be stuck in this case if it would include the primary template when ordering, rising an ambiguity. In this case, i believe the primary template will never be taken regardless of what arguments you use. It would be interesting to know a trick to still access members of the primary template, though, if you have any idea lemme know. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |