Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specialization of class template parameter compiles in GCC, Clang and MSVC but GCC selects another specialization [duplicate]

Consider the following code:

#include <type_traits>

template<template<class...> class T, class... U>
struct is_specialization_of : std::false_type{};

template<template<class...> class T, class... U>
struct is_specialization_of<T, T<U...>> : std::true_type{};

template<class T, class U = int>
struct test{};

// (1) ok
static_assert(is_specialization_of<test, test<int>>::value, "1");

template<class T>
using alias = test<T>;

// (2) fails
static_assert(is_specialization_of<alias, alias<int>>::value, "2");

int main()
{
}

Why does (2), i.e. static_assert that uses alias template, fail?

How does the template argument deduction process in (2) differ from the one in (1)?

like image 547
Igor R. Avatar asked Apr 25 '17 19:04

Igor R.


People also ask

Why does the need of template specialization arise?

It is possible in C++ to get a special behavior for a particular data type. This is called template specialization. Template allows us to define generic classes and generic functions and thus provide support for generic programming.

What is function template specialization?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.

What is ctad c++?

Alex April 24, 2022, 7:49 pm August 24, 2022. Class template argument deduction (CTAD) C++17. Starting in C++17, when instantiating an object from a class template, the compiler can deduce the template types from the types of the object's initializer (this is called class template argument deduction or CTAD for short).

What is template argument in C++?

A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.


1 Answers

This is CWG issue 1286. The question is: are alias and test equivalent? There used to be an example in [temp.type] which suggested that y and z have the same type here:

template<template<class> class TT> struct X { };
template<class> struct Y { };
template<class T> using Z = Y<T>;
X<Y> y;
X<Z> z;

The example was corrected as part of CWG defect 1244 - which indicated correctly that there is no wording in [temp.alias] that actually specifies that alias templates are equivalent to the templates they alias. The only wording there refers to equivalence of alias template specializations:

When a template-id refers to the specialization of an alias template, it is equivalent to the associated type obtained by substitution of its template-arguments for the template-parameters in the type-id of the alias template.

The intent is apparently that y and z do have the same type in this example, meaning that Z and Y are actually equivalent. But unless and until the wording in the resolution is adopted, they are not. Today, alias and test are not equivalent but alias<int> and test<int> are. This means that is_specialization_of<alias, alias<int>> is is_specialization_of<alias, test<int>>, where alias is unique from test, which would not match your partial specialization and thus be false_type.

Moreover, even with the adoption of the wording in #1286, test and alias are still not equivalent for the obvious reason that test takes two template parameters and alias takes one template parameter. The example in the resolution wording mimics your example and clarifies the intent here:

template<typename T, U = T> struct A;

// ...

template<typename V>   
  using D = A<V>;      // not equivalent to A:
                       // different number of parameters
like image 88
Barry Avatar answered Oct 20 '22 19:10

Barry