c++templatesc++20non-type

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


While trying to use a compile time std::array in a variadic template, I wrote this partial template specialization:

template <typename array_wrapper> struct Test1;
template <std::size_t... A> struct Test1<any_type<std::array<std::size_t, sizeof...(A)>{A...}>> {}; //(2)

which leads to a compilation error <Expression> has incomplete type and cannot be defined for my attempts to partial template specialization for Test1 and Test2 when I am trying to use it; hence -- as I understand it -- the usage (3) does not match the definition (2):

int main() {
  Test1<any_type<std::array<std::size_t, 2>{1, 2}>> a; // (3)
}

I don't understand why this is the case though. When experimenting with the example, I realize that this happens when I am 'hiding' the content of the parameter pack in my any_type struct:

#include <array>

template <auto f> struct any_type;

template <typename array_wrapper> struct Test1;
template <std::size_t... A> struct Test1<any_type<std::array<std::size_t, sizeof...(A)>{A...}>> {};

template <typename array_wrapper> struct Test2;
template <int... A> struct Test2<any_type<std::get<0>(A...)>> {};

template <typename array_wrapper> struct Test3;
template <int A> struct Test3<any_type<A>> {};

int main() {
  //Test1<any_type<std::array<std::size_t, 2>{1, 2}>> a;
  //Test2<any_type<1>> b;
  Test3<any_type<1>> ok;
}

Test1 and Test2 fail with the same error, and Test3 works fine. Why does the partial template specialization 'fail' in the frist two cases? As I understand it, the declaration provides the 'interface' in order to use the struct, and the arguments in the specialization are matched to teh arguments which are actually provided.

Code The code can be found here.

Compile options: I useg++-10.0 (GCC) 10.0.1 20200124 (experimental) and compile via g++ -std=c++2a file.cc, c++2a is required because I use non-type template parameters.


Solution

  • There are a finite set of patterns that template arguments can be deduced from. For template non-type arguments, that set is just (from [temp.deduct.type]/8):

    ... and that's it. Your Test3 matches the 2nd form, and the other two don't match at all.

    It's not clear how the Test2 example would work at all. The Test1 example may be something we want to consider as the use of non-type template parameters proliferates after C++20, but it's just not something that's currently valid.