我正在使用可变参数包进行基于策略的类设计。
template <APITypes APIType, class... Policies>
class IShader : public Policies... {
};
调用时定义策略,如果未指定,则使用默认值定义策略。当我需要添加另一个可变参数包时会出现问题:
template <AttributeType... Attributes, APITypes APIType, class... Policies>
class IShader : public Policies... {
};
这会导致错误“模板参数包必须是最后一个模板参数”。我打算使用属性包来更改至少一个策略的行为。但我无法弄清楚如何在一个模板类中获得两个可变参数包。
答案 0 :(得分:8)
我认为最简单的答案是为参数包创建模板类型包装器。例如:
template <AttributeType... T>
struct Attributes {};
template <typename... T>
struct Policies {};
然后您可以声明您的IShader类型:
template <typename... T>
class IShader;
将您的实施创建为专业化。请注意,在专门化中,您可以拥有多个参数包参数。
template <AttributeType... AttributeList, ApiTypes APIType, typename... PolicyList>
class IShader<Attributes<AttributeList...>, ApiType, Policies<PolicyList...>>
: public PolicyList...
{
...
};
然后你甚至可以允许用户以不同的顺序指定参数(如果通过继承这样做,请确保转发构造函数):
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;
};
如果你真的很喜欢,你甚至可以使用元编程技巧来允许任何顺序的参数,而无需枚举所有的命令。这留给读者练习。 :)
答案 1 :(得分:6)
在讨论评论中,您表示愿意考虑某种间接,或者#34;属性列表的某种包装&#34;。
基于std::tuple
的轻量级包装器以及专业化可能在这里工作:
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... {
// ...
};
这里的目标是使用以下行的模板实例:
IShared<std::tuple<Attribute1, Attribute2>, APITypeFoo,
std::tuple<Policy1, Policy2>> ishared_instance;
并指出这将与专门的模板声明相匹配,此时两个参数包都可供单独使用的模板专业化。
答案 2 :(得分:0)
创建一个嵌套类,每层有一个可变包。本质上:
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;
//...
在两个类之外都定义Type
的任何函数,但在标头内部,否则gcc会感到困惑。
有关更完整的用例,请参见my answer here