模板类的多变量参数包

时间:2016-05-13 02:39:45

标签: c++ c++14 variadic-templates

我正在使用可变参数包进行基于策略的类设计。

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

};

调用时定义策略,如果未指定,则使用默认值定义策略。当我需要添加另一个可变参数包时会出现问题:

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

};

这会导致错误“模板参数包必须是最后一个模板参数”。我打算使用属性包来更改至少一个策略的行为。但我无法弄清楚如何在一个模板类中获得两个可变参数包。

3 个答案:

答案 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