2015-06-19 19 views
1

考虑以下代码撰写的std :: integral_constant值

#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 
} 

我试图定义,ComposeValues<T, Value, Pack...>因此,上述在main()可以写成ComposeValues<Object, Object0, ThingValue, ObjectValue>::value。那么这可以扩展到任何数量的这样的组合物。这不是一件绝对重要的事情,但我认为定义这样的事情是一个很好的小练习。但我的语法有困难:

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...> { 
    static auto value = First<typename ComposeValues<T, Value, Rest...>::value>::value; 
}; 

template <typename T, T Value, template <T> class Last> 
struct ComposeValues<T, Value, Last> : std::integral_constant<T, Last<Value>::value> {}; // Won't compile. 

这是甚至可能我正在尝试做什么?

回答

2

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

解决此问题的一种方法是将您的枚举编码为某种类型的模板,它可以不加区分地保存它们。一个可能的方法是将枚举视为int s,并让用户担心传入的合理类型。

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

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 
+0

[Demo](https:// ideone。 com/OzYg2O) – TartanLlama

+0

这样做的一个缺点是最终的类型被删除了,但是你可以很容易地处理这个问题,并且最后执行到'T'。 – TartanLlama

+0

好吧,我研究了你的解决方案,我明白了。但是最后一个写'ComposeValues ,Wrap > :: value'的建议会遇到和我原来的问题一样的问题,不是吗?由于'ThingValue'和'ObjectValue'不是类型,而是模板(使用不同的非类型参数)。如果我们可以这样写,或者'ComposeValues > :: value',那么我的原始方法也是可能的,对吧?我不明白'ThingValueWrapper'和'ObjectValueWrapper'可以很好地参数化到一个家庭中。 – prestokeys