6

In C++20, we have better NTTPs, which allows literal class types:

template <typename T>
struct A{};

template <A> // note: it is a placeholder for NTTP A<T>
struct B{};

But when I try to specialize a template for B:

template <typename>
struct is_B{};

template <A x>
struct is_B<B<x>>{}; // error!!!

The compiler (GCC 10 or GCC 11(trunk)) dumps a bunch of errors:

prog.cc:11:15: error: class template argument deduction failed:
   11 | struct is_B<B<x>>{};
      |               ^
prog.cc:11:15: error: no matching function for call to 'A(A<...auto...>)'
prog.cc:2:8: note: candidate: 'template<class T> A()-> A<T>'
    2 | struct A{};
      |        ^
prog.cc:2:8: note:   template argument deduction/substitution failed:
prog.cc:11:15: note:   candidate expects 0 arguments, 1 provided
   11 | struct is_B<B<x>>{};
      |               ^
prog.cc:2:8: note: candidate: 'template<class T> A(A<T>)-> A<T>'
    2 | struct A{};
      |        ^
prog.cc:2:8: note:   template argument deduction/substitution failed:
prog.cc:11:15: note:   mismatched types 'A<T>' and 'A<...auto...>'
   11 | struct is_B<B<x>>{};
      |               ^
prog.cc:11:16: error: template argument 1 is invalid
   11 | struct is_B<B<x>>{};
      |                ^~

I found a solution, which is giving an explicit argument to A:

template <typename T, A<T> x>
struct is_B<B<x>>{};

But it is redundant, and cannot solve the same error when A used in using:

template <A x>
using B_t = B<x>; // same error!!!

So is there another solution?

Twice
  • 95
  • 4
  • Your piece of code now compiles with GCC 11 20201207. It seems that they have fixed the bug. No idea of what patch fixed it or if it was backported to the GCC10 branch, though. – metalfox Dec 09 '20 at 16:20
  • I think I figured it out. If I'm not mistaken, it has been backported to GCC 10 by this commit: [3e7a892cc5bdeb5518888f2ca176d96cc720ec5f](https://gcc.gnu.org/viewcvs?rev=279228&root=gcc&view=rev). – metalfox Dec 09 '20 at 16:28

1 Answers1

3

It seems that GCC doesn't like placeholders for deduced class types as NTTP, which should be accepted as per [temp.param]/6 (emphasis mine):

A non-type template-parameter shall have one of the following (possibly cv-qualified) types:

  • a structural type (see below),
  • a type that contains a placeholder type ([dcl.spec.auto]), or
  • a placeholder for a deduced class type ([dcl.type.class.deduct]).

There's already a related bug report (PR96331, see the example provided by @TC).

metalfox
  • 6,301
  • 1
  • 21
  • 43