Mixing types and nontypes in variadic template par

2020-08-13 07:25发布

问题:

Is it possible to do mixing of types and nontypes in variadic template parameters? If I were to pass a std::array for instance to this class as parameter T, I would need to also pass a type for the array and a length, but the way I tried it below causes an error when encountering a value, because it only expects types for Types:

template <
    template<class, std::size_t>  class T,
    class ... Types>
class C {

    T<Types...> storage;
};

int main(){
    C<std::array, int, 3> c;
}

Error message:

error: template argument for template type parameter must be a
      type
    Container<std::array, int, 3> c;
                               ^

Is there a way to pass types and values in a variadic context?

回答1:

As I see, you alreadty hardcoded the number and types of parameter the class T must take as template parameter. You don't need variadic templates here. Just do this instead:

template <
    template<class, std::size_t>  class T,
    class A, std::size_t N>
class C {

    T<A, N> storage;
};

int main(){
    C<std::array, int, 3> c; // works!
}

If you wish to use variadic templates, then put it in the template template parameter too:

template <
    template<typename...>  class T,
    typename... Types>
class C {

    T<Types...> storage;
};

If you wish to use that version but still want to use std::array, you can create an alias to std::array that already has a size:

template<typename T>
using array3 = std::array<T, 3>;

C<array3, int> c;

Alternatively, you can also create some sort of template template alias that let you choose the size:

template<std::size_t n>
struct sized_array {
    template<typename T>
    using array = std::array<T, n>;
};

C<sized_array<5>::array, int>;


回答2:

Is it possible to do mixing of types and nontypes in variadic template parameters?

No. You can't mix and match. But since you can wrap a value in a type but not the other way around, you can just stay in the world of types:

template <template<class...> class T, class ... Types>
class C {    
    T<Types...> storage;
};

And then it's just a matter of making std::array work with just types:

template <class T, class N>
using my_array = std::array<T, N::value>;

template <size_t N>
using size_ = std::integral_constant<size_t, N>;

So your original example becomes:

C<my_array, int, size_<3>> c;