Я не знаю, приемлемо ли это для вас, но я предлагаю другой обходной путь для вашей исходной проблемы: преобразуйте в параметр template-template также контейнер.
Я имею в виду ... вместо
template <class... Ts, int... Ns>
void error(Base<Ts, Ns...> const &... arg)
{ }
Я предлагаю
template <template <typename, int...> class C, typename ... Ts, int ... Ns>
void error(C<Ts, Ns...> const &...)
{ }
Если вы хотите быть уверены, что C
получено из Base
, вы можете навязать это через SFINAE;используя свертывание шаблонов в C ++ 17, вы можете написать
template <template <typename, int...> class C, typename ... Ts, int ... Ns>
std::enable_if_t<(... && std::is_base_of_v<Base<Ts, Ns...>, C<Ts, Ns...>>)>
error(C<Ts, Ns...> const &...)
{ }
Вы также можете преобразовать C
в вариационный список шаблонов-шаблонов и принять сочетание Base
и Derived
template <template <typename, int...> class ... Cs, typename ... Ts, int ... Ns>
std::enable_if_t<(... && std::is_base_of_v<Base<Ts, Ns...>, Cs<Ts, Ns...>>)>
error(Cs<Ts, Ns...> const &...)
{ }
Ниже приведен пример полной компиляции (как g ++, так и clang ++)
#include <type_traits>
template <typename, int...>
class Base {};
template <typename, int...>
class Wrong {};
template <typename T, int... Ns>
class Derived : public Base<T, Ns...> {};
template <template <typename, int...> class ... Cs, typename ... Ts, int ... Ns>
std::enable_if_t<(... && std::is_base_of_v<Base<Ts, Ns...>, Cs<Ts, Ns...>>)>
error(Cs<Ts, Ns...> const &...)
{ }
int main ()
{
Base<int, 1, 2, 3> a;
Base<long, 1, 2, 3> b;
error(a, b);
Derived<int, 1, 2, 3> c;
Derived<long, 1, 2, 3> d;
error(c, d);
error(a, c, b, d);
Wrong<int, 1, 2, 3> e;
Wrong<long, 1, 2, 3> f;
//error(e, f); // compilation error
//error(a, c, e, b, d, f); // compilation error
}