考虑这段代码
#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.
我想做的甚至有可能吗?
最佳答案
您遇到的问题是,您不能混合使用不同非类型参数的模板模板。在您的示例中,这意味着ObjectValue
和ThingValue
无法绑定(bind)到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