From: Edward Diener on
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
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
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! ]