编写std :: integral_constant值

时间:2015-06-19 10:35:11

标签: c++ templates c++11 variadic

考虑这段代码

<data>

我正在尝试定义#include <iostream> #include <type_traits> enum Thing {Thing0, Thing1, Thing2, NumThings}; enum Object {Object0, Object1, Object2, NumObjects}; template <Thing> struct ThingValue; template <> struct ThingValue<Thing0> : std::integral_constant<int, 5> {}; template <> struct ThingValue<Thing1> : std::integral_constant<int, 2> {}; template <> struct ThingValue<Thing2> : std::integral_constant<int, 12> {}; template <Object> struct ObjectValue; template <> struct ObjectValue<Object0> : std::integral_constant<Thing, Thing2> {}; template <> struct ObjectValue<Object1> : std::integral_constant<Thing, Thing0> {}; template <> struct ObjectValue<Object2> : std::integral_constant<Thing, Thing1> {}; int main() { std::cout << ThingValue<ObjectValue<Object0>::value>::value << '\n'; // 12 } ,以便main()中的上述内容可以写为ComposeValues<T, Value, Pack...>。那么这可以扩展到任何数量的这种组合物。这不是绝对重要的事情,但我认为定义这样的事情是一个很好的小练习。但我的语法有困难:

ComposeValues<Object, Object0, ThingValue, ObjectValue>::value

这甚至可能是我想要做的吗?

1 个答案:

答案 0 :(得分:2)

您遇到的问题是您不能混合使用不同非类型参数的模板模板。在您的示例中,这表示ObjectValueThingValue无法绑定到template <typename> class...

解决这个问题的一种方法是将您的枚举编码为某种类型的模板,这种模板可以无差别地保存它们。一种可能的方法是将枚举视为int,并让用户担心传递合理的类型。

首先,我们围绕您当前的类型创建包装器:

template <typename> struct ThingValueWrapper;
template <int I>
struct ThingValueWrapper<std::integral_constant<int,I>> 
    : ThingValue<static_cast<Thing>(I)>
{};

template <typename> struct ObjectValueWrapper;
template <int I>
struct ObjectValueWrapper<std::integral_constant<int, I>> 
    : ObjectValue<static_cast<Object>(I)>
{};

然后我们可以做一些与你原来的相似的东西:

template <typename T, T Value, template <typename> class...> struct ComposeValues;

template <typename T, T Value, 
          template <typename> class First, 
          template <typename> class... Rest>
struct ComposeValues<T, Value, First, Rest...>
    : std::integral_constant<int,
                             First<typename ComposeValues<T, Value, Rest...>::type>::value>
{};

template <typename T, T Value>
struct ComposeValues<T, Value> : std::integral_constant<int, static_cast<int>(Value)> {};

与原始用例的唯一区别是我们需要使用包装器而不是原始的枚举特性:

ComposeValues<Object, Object0, ThingValueWrapper, ObjectValueWrapper>::value