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. :)
md5i
source share