c++ - 组成 std​​::integral_constant 值

标签 c++ templates c++11 variadic

考虑这段代码

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

这甚至可能是我正在尝试做的事情吗?

最佳答案

您遇到的问题是您不能混合采用不同非类型参数的模板模板。在您的示例中,这意味着 ObjectValueThingValue无法绑定(bind)到 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

关于c++ - 组成 std​​::integral_constant 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30936019/

相关文章:

C++11: 结构时间间隔

ruby-on-rails-3 - 如何在 gem 中覆盖 Rails 生成器模板?

templates - Resharper 6.0 模板编辑器不再工作

c++ - 使用 "extern template"时专门化模板的正确方法是什么?

c++ - 将类型转换/更改为指向类型的指针 (SDL_Rect)

c++ - 错误 : expected constructor, 析构函数,或源文件中用户定义类的 '&' token 之前的类型转换

c++ - 在 main 外部和变量声明之前调用 srand

php - 如果我的 PHP 不使用模板引擎,我的代码应该是什么样的?

c++ - clang 根据其重载之一拒绝带有尾随 decltype 返回类型的模板调用是否正确?

c++ - 如何使从科学计数法的转换更精确?