Matching alias template as template argument
Asked Answered
S

2

15

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)?

Sudatorium answered 25/4, 2017 at 19:13 Comment(1)
CWG 1286Insolate
F
15

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
Foreandaft answered 26/4, 2017 at 13:54 Comment(2)
Interestingly, if we change test to get a single template argument, then (2) still does not compile with any Clang and with GCC < 4.9. It means that GCC >= 4.9 already implements #1286.Sudatorium
@IgorR. Well, 1286 isn't adopted. So it's arguably incorrect.Foreandaft
H
2

I think that name of alias template without template arguments list is not equivalent to the name of associated type. Because standard specifies only one such situation:

14.5.7 Alias templates [temp.alias]

  1. 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. [Note: An alias template name is never deduced.—end note ]

and this works fine:

static_assert(is_specialization_of<test, alias<int>>::value, "2");
Hearing answered 25/4, 2017 at 19:39 Comment(3)
Then, why if we remove test's second template argument U, everything compiles well?Sudatorium
Is it because, "An alias template name is never deduced". A partial specialization is chosen by attempting to deduce the specialization's parameters. When the compiler is attempting to deduce T in the specialization, it doesn't consider alias as a possibility?Ramiform
This is actually 17.5.7 now, after this; please use permanent names, i.e. [temp.alias] in this case. (That has the upside of being linkable to: http://eel.is/c++draft/temp.alias.)Hangover

© 2022 - 2024 — McMap. All rights reserved.