Partial specialization of single type template parameter class template using non-type template parameter through a dependent type

dfri :

All standard references below refers to N4659: March 2017 post-Kona working draft/C++17 DIS.


Consider the following snippet:

#include <type_traits>

template <int N> struct num {};

template <typename> struct A;

// (1)
template <int N> struct A<num<N>> { using type = bool; };

// (2)
template <long N> struct A<num<N>> { using type = char; };

static_assert(!std::is_same_v<long, int>, "");

// (A)
static_assert(std::is_same_v<A<num<1>>::type, bool>, "");

int main() {}

The static_assert at (A) is successful for GCC, but fails for Clang:

error: static_assert failed due to 
       requirement 'std::is_same_v<char, bool>' ""

Essentially, GCC picks the perfectly matching specialization (1), whereas Clang picks the specialization (2).

Similarly, if we remove the assertions as well as specialization (1):

template <int N> struct num {};

template <typename> struct A;

// (2)
template <long N> struct A<num<N>> { using type = char; };

int main() {
  A<num<1>> a{};
  (void)a;
}

Then GCC fails to compile the program whereas Clang accepts it.

GCC:

error: variable '`A<num<1> > a`' has initializer but incomplete type

This behaviour holds over various GCC and Clang versions, as well as various C++ language levels over these version (C++11, C++14, C++17, C++2a).

Question

  • Is the first snippet above in fact ill-formed (no diagnostic required?), or is either GCC or Clang wrong?

My guess is that this is ill-formed, but haven't been able to apply a relevant part of [temp.class.spec] to reject it. Perhaps [temp.class.spec]/8.1?

[temp.class.spec]/8.1 The type of a template parameter corresponding to a specialized non-type argument shall not be dependent on a parameter of the specialization. [ Example: [...] — end example ]

bogdan :

As far as I can tell, the first snippet is ill-formed (and a diagnostic is required); compilers should reject the program because of the partial specialization (2).

[temp.deduct.type]/18 applies here:

If P has a form that contains <i>, and if the type of i differs from the type of the corresponding template parameter of the template named by the enclosing simple-template-id, deduction fails. [...]

The associated example in the Standard uses a function template, but is otherwise very similar.

So the template argument of the partial specialization (2) can never be deduced, and [temp.class.spec.match]/3 applies:

If the template arguments of a partial specialization cannot be deduced because of the structure of its template-parameter-list and the template-id, the program is ill-formed.


Interestingly, I couldn't find a compiler that diagnoses this issue, not even EDG in strict mode. We could speculate that most compiler writers consider the benefits of having a diagnostic here not to be worth the effort of implementing the checks. This could mean that we might see the requirement in the paragraph above change in the future from ill-formed to ill-formed, no diagnostic required. However, this is pure speculation. In any case, I don't see it ever changing to well-formed; I can't think of a valid use for a partial specialization that never matches.


The wording of [temp.deduct.type]/18 was clarified by the resolution of CWG2091.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Non-type template parameter dependent on a default template type parameter

Template function dependent on non-type parameter

How to perform partial template specialization with a parameter pack and non-type template value?

Non type template parameter

C++ Template specialization by type of non-type parameter

Alias template, partial specialization and the invalid parameter type void

Partial template specialization of non type argument not allowed

Obtaining variadic template non-type parameter through explicit class

Using non-type template template parameter in template specialisation

C++ template specialization with any non-type parameter

template non-type template parameter

Alias Template with non-type template parameter

Syntax for an instance of a class template as a non-type template parameter

Variadic template partial specialization of a class to restrict type of template arguments

Specialize template template parameter with a non-type template parameter

Partial template specialization with second template type

Class type non-type template parameter initialization does not compile

Auto non-type template parameter: ambiguous partial specializations in Clang

Constraing template parameter by another template with any specialization type

Getting the type of a template template parameter with using

template template parameter of unknown type

template type deduction of template parameter

Determine type of template parameter in template

Function template taking a template non-type template parameter

Calling template function with non-type template parameter using class attribute

Template template parameter with mixed type and non-type variadic parameters

Type trait dependent specialization of template function

Template parameter as return type

How to define a class template with reference type template parameter of template template parameter type