2015-06-19 3 views
1

Рассмотрим этот кодСоставление СТД :: 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...> так, что выше в основной() можно записать в виде 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

Проблема, с которой вы сталкиваетесь, заключается в том, что вы не можете смешивать шаблоны шаблонов, которые принимают разные аргументы, отличные от типа. В вашем примере это означает, что ObjectValue и ThingValue не могут связываться с 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