简体   繁体   中英

template specialization with default parameters

The following code compiles. Anyone can explain why? I've been digging the standard to figure out why it's legal.

template <bool B, typename T = void> struct enable_if { };
template <typename T> struct enable_if<true, T> {
    typedef T type;
};
template <typename T, typename Enable = void> struct A;
template <typename T> struct A<T, typename enable_if<(sizeof(T) <= ~0ULL)>::type> {
    void f() { }
};
int main() {
    A<int> a;
    a.f();
}

At the statement:

A<int> a;

As there's only one template paramerter "int", the compiler should go to use the primary template, which is:

template <typename T, typename Enable = void> struct A;

which is undefined, thus causing an error.

From § 14.5.5.1

1 When a class template is used in a context that requires an instantiation of the class, it is necessary to determine whether the instantiation is to be generated using the primary template or one of the partial specializations. This is done by matching the template arguments of the class template specialization with the template argument lists of the partial specializations.

— If exactly one matching specialization is found, the instantiation is generated from that specialization.

Let's try to figure out what's going on here:

// definition of enable_if, second parameter is defaulted to void
template <bool B, typename T = void> 
struct enable_if { };

// specialization of enable_if, if first parameter is true, 
// enable_if has a typedef for the second parameter
template <typename T> 
struct enable_if<true, T> {
    typedef T type;
};

// definition of struct A, second parameter defaults to void
template <typename T, typename Enable = void> 
struct A;

// specialization of struct A, second parameter 
// is obtained from the enable_if::type typedef
// the first parameter of enable_if is true if the size of T
// is smaller than the max long long (~0 --> all F)
template <typename T> 
struct A<T, typename enable_if<(sizeof(T) <= ~0ULL)>::type> {
    void f() { }
};

int main() {
    // So we attempt the specialization for struct A<int,enable_if...>
    // The expression of enable_if evaluates to...
    // (sizeof(int) <= ~0ULL) == true
    // ... so it applies the specialization of enable_if<true,void>
    //     (second parameter is void because none is provided, so it 
    //     uses the default.
    // so the enable_if template is valid (selected the specialization)
    // and that means that the struct A<int,enable_if> specialization
    // is valid too, so it is selected.
    A<int> a;
    a.f();
}

The compiler uses the template A<int, enable_if<true>:::type > when you declare A<int> since sizeof(int) <= ~0ULL evaluates to true .

There is no problem with enable_if<true>::type because the compiler is able to use enable_if<true, true>::type .

When you consider your enable_if:

template <bool B, typename T = void> struct enable_if{ };

template <typename T> struct enable_if<true, T> 
{
    typedef T type;
};

in

void test_EnableIf
{
 static_assert(
   std::is_same<
     enable_if<(sizeof(int) > 0)>::type,
     void>::value, "test_EnableIf failed." );
}

the result (type) is void, as no type was specified (as second template parameter). The specialization of enable_if is selected because of the boolean expression being true, and the default parameter is selected (from primary template) because no other was provided, and hence type is void, but NOTE that the definition of type does exist (as the specialization was selected).

Now, in your definition of A...

template <typename T, typename Enable = void> struct A; 
template <typename T> 
struct A<T, typename enable_if<
  (sizeof(T) <= ~0ULL)>::type> 
{
    void f() { } 
};

...because type does exist in enable_if, it is a better match, which causes the specialization to be selected, and hence compiles.

A trivial example which amounts to the same thing is the following:

template <class T, class U = void>
struct X;

template <class T>
struct X<T,void>
{
  static int foo(){ return 0; }
};

int main()
{
  return X<int>::foo();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM