c++c++17variadic-templatestemplate-templates

Issue with variadic template template parameter pack


Consider the following example:

template< class A, int B, class C>
struct Obj {
A a_obj;
static constexpr int b_value = B;
C c_obj;

};

template< template<class... > class ... Templates >
struct Foo;


template<>
struct Foo<Obj> {

Obj<void*, 5, float> obj;
};


int main() {
Foo<Obj> foo;

};

This is failing on me (g++ 7.2, with -std=c++17 with the following errors:

templ.cpp:16:15: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class ...> class ... Templates> struct Foo’
   16 | struct Foo<Obj> {
      |               ^
templ.cpp:16:15: note:   expected a template of type ‘template<class ...> class ... Templates’, got ‘template<class A, int B, class C> struct Obj’
templ.cpp: In function ‘int main()’:
templ.cpp:23:8: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class ...> class ... Templates> struct Foo’
   23 | Foo<Obj> foo;
      |        ^
templ.cpp:23:8: note:   expected a template of type ‘template<class ...> class ... Templates’, got ‘template<class A, int B, class C> struct Obj’

It seems that it is not getting matched, although it doesn't look like it thinks the template<class ...> class ... Templates is a syntax error, hence the parameter-parameter pack is parsing

Is this type of declaration (with some types, a constant value, then more types, or perhaps constant values at the end) unmatchable with variadic template template pack syntax? or perhaps I'm not using the syntax right

Edit

I modified the version to avoid non-types in declarations, but the problem persists:

template< template <class, class> class B, class A, class C>
struct Obj {
A a_obj;
//static constexpr int b_value = B;
B< C, A > b_obj;
C c_obj;

};

template< template<typename... > typename ... Templates >
struct Foo;

template<class A, class V>
struct Bar {
A a_obj;
//static constexpr int value = V;
V obj;
};

template<>
struct Foo<Obj> {

Obj<Bar, void*, float> obj;
};


int main() {
Foo<Obj> foo;

};

So it seems that is not that just non-types and types cannot be matches on a variadic pack, but any mixture of types and templates

I also tried adding an additional variadic pack:

template< template<typename... > typename ... Templates, class ... Types >
struct Foo;

But then I get:

error: parameter pack ‘template<class ...> class ... Templates’ must be at the end of the template parameter list
   12 | template< template<typename... > typename ... Templates, class ... Types >

Solution

  • int B is a non-type template parameter. You have to declare Templates as template<class, auto, class> class if you want it to work with that particular class template, or redefine Obj to take a std::integral_constant to pass a value encapsulated in a type:

    template<class A, class B, class C>
    struct Obj {
        A a_obj;
        static constexpr int b_value = B::value;
        C c_obj;
    };
    
    template<template<class...> class... Templates>
    struct Foo;
    
    template<>
    struct Foo<Obj> {
        Obj<void*, std::integral_constant<int, 5>, float> obj;
    };
    
    int main() {
        Foo<Obj> foo;
    }
    

    Try it on godbolt.org.