Multiple Variadic Options Package for Template Class

I am using varadic policy packages for development based on policies.

template <APITypes APIType, class... Policies> class IShader : public Policies... { }; 

Policies are defined upon invocation or by default if none are specified. The problem arises when I need to add another package of variational parameters:

 template <AttributeType... Attributes, APITypes APIType, class... Policies> class IShader : public Policies... { }; 

This results in the error "Template parameter package must be the last template parameter." I plan to use the attribute package to change the behavior of at least one of the policies. But I can’t decide how to get two packages of variable parameters in one class of templates.

+8
c ++ c ++ 14 variadic-templates
source share
3 answers

In the comments to the discussion, you expressed your readiness to consider some kind of indirectness or "shell of some kind for a list of attributes."

The lightweight wrapper std::tuple can work here, along with the specialization:

 template <typename attribute_tuple, APITypes APIType, typename policy_tuple> class IShader; template <AttributeType... Attributes, APITypes APIType, class... Policies> class IShader<std::tuple<Attributes...>, APIType, std::tuple<Policies...>> : public Policies... { // ... }; 

The goal here is to use a template instance in the lines:

 IShared<std::tuple<Attribute1, Attribute2>, APITypeFoo, std::tuple<Policy1, Policy2>> ishared_instance; 

And cross your fingers to match the declaration of the specialized template, after which both packages of parameters are available for the specialized specialization of the template separately.

+6
source share

I think the simplest answer is to create template type wrappers for your parameter packages. For example:

 template <AttributeType... T> struct Attributes {}; template <typename... T> struct Policies {}; 

Then you can declare your type of IShader:

 template <typename... T> class IShader; 

Create your implementation as a specialization. Note that in a specialization, you can have several arguments to a parameter package.

 template <AttributeType... AttributeList, ApiTypes APIType, typename... PolicyList> class IShader<Attributes<AttributeList...>, ApiType, Policies<PolicyList...>> : public PolicyList... { ... }; 

Then you can even allow the user to specify arguments in different orders (make sure you redirect constructors if you do this through inheritance):

 template <AttributeType... AttributeList, ApiTypes APIType, typename... PolicyList> struct IShader<ApiType, Policies<PolicyList...>, Attributes<AttributeList...> : public IShader<Attributes<AttributeList...>, ApiType, Policies<PolicyList...>> { using IShader<Attributes<AttributeList...>, ApiType, Policies<PolicyList...>>::IShader; }; 

If you really love, you can even use metaprogramming tricks to resolve arguments in any order without listing all orders. This remains as an exercise for the reader. :)

+8
source share

Create a nested class in which each layer will have one package with variable values. In fact:

 template<class... ArgsA> class Wrapper { public: template<class... ArgsB> class Type { //Here you have access to both template packs //... } } //Use like this: Wrapper<int, char, long unsigned int>::Type<float, double> a; //... 

Define any function from Type outside of both classes, but inside the header, otherwise gcc will get confused.

For more complete use see my answer here

0
source share

All Articles