I am using variadic parameter packs for policy based class design.
template <APITypes APIType, class... Policies>
class IShader : public Policies... {
};
Policies are defined when called or with defaults if none are specified. The problem comes when I need to add another variadic parameter pack:
template <AttributeType... Attributes, APITypes APIType, class... Policies>
class IShader : public Policies... {
};
This results in the error "Template parameter pack must be the last template parameter". I am planning to use the attribute pack to change the behaviour of at least one of the policies. But I can't work out how to get two variadic parameter packs in one template class.
A variadic template is a class or function template that supports an arbitrary number of arguments. This mechanism is especially useful to C++ library developers: You can apply it to both class templates and function templates, and thereby provide a wide range of type-safe and non-trivial functionality and flexibility.
Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration. However, variadic templates help to overcome this issue.
Variadic functions are functions that can take a variable number of arguments. In C programming, a variadic function adds flexibility to the program. It takes one fixed argument and then any number of arguments can be passed.
Parameter packs (C++11) A parameter pack can be a type of parameter for templates. Unlike previous parameters, which can only bind to a single argument, a parameter pack can pack multiple parameters into a single parameter by placing an ellipsis to the left of the parameter name.
I think the simplest answer is to create template type wrappers for your parameter packs. For example:
template <AttributeType... T>
struct Attributes {};
template <typename... T>
struct Policies {};
Then you can declare your IShader type:
template <typename... T>
class IShader;
Create your implementation as a specialization. Note that in a specialization, you can have multiple parameter pack arguments.
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 the arguments in different orders (make sure you forward the constructors if doing it this way via 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're being really fancy, you can even use metaprogramming tricks to allow the arguments in any order without enumerating all orders. This is left as an exercise to the reader. :)
In the discussion comments you expressed a willingness to consider some kind of indirection, or "a wrapper of some kind for the attribute list".
A lightweight std::tuple
-based wrapper, together with specialization, might work here:
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 along the lines of:
IShared<std::tuple<Attribute1, Attribute2>, APITypeFoo,
std::tuple<Policy1, Policy2>> ishared_instance;
And cross your fingers that this is going to match the specialized template declaration, at which point both parameter packs are available for the template specialization to use, individually.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With