【问题标题】:Can I use type traits to deduce the type of an enum from an enum value in c++?我可以使用类型特征从 C++ 中的枚举值推断出枚举的类型吗?
【发布时间】:2016-06-06 16:26:41
【问题描述】:

在下面的示例中,我创建了一些以枚举值为模板的流畅方法,用于测试值是否包含特定标志。

#include <type_traits>

// Scoped flags enum
enum class Flags {
    One = 1 << 0,
    Two = 1 << 1
};

// Template method for enum bitwise and operator
template< typename enum_type >
constexpr enum_type bitwise_and_operator(enum_type lhs, enum_type rhs) {
    typedef typename std::underlying_type<enum_type>::type fundamental_type;
    return static_cast<enum_type>(static_cast<fundamental_type>(lhs) & static_cast<fundamental_type>(rhs));
}

// Flags and operator
constexpr Flags operator&(Flags lhs, Flags rhs) {
    return bitwise_and_operator<Flags>(lhs, rhs);
}

// Template method for enum flag
template< typename enum_type, enum_type enum_value >
constexpr bool Flagged(enum_type type) {
    return (type & enum_value) == enum_value;
}

// Has flag one?
constexpr bool HasOne(Flags flags) {
    return Flagged<Flags, Flags::One>(flags);
};

// Has flag two?
constexpr bool HasTwo(Flags flags) {
    return Flagged<Flags, Flags::Two>(flags);
};


int main() {

    auto flag = Flags::One;

    auto True = HasOne(flag);
    auto False = HasTwo(flag);

    return 0;
}

包含两个模板参数,Flags 和 Flags::One,可能比编译器需要的信息更多。

是否可以构造一个可以调用的模板:

constexpr bool HasOne(Flags flags) {
    return Flagged<Flags::One>(flags);
};

如何构造一个在编译时从值推断枚举类型的方法?或者这个问题有其他编译时解决方案吗?

提前致谢。

【问题讨论】:

  • 我认为不需要将值作为模板参数。
  • 感谢克里斯,这不是需要,而是将更多计算从运行时转移到编译时的努力的一部分。当性能很重要时,一系列可预计算的类型非常有用。此外,要使用运算符重载而不依赖于底层类型,我相信类型上的模板参数是必需的......但是是的,有更通用的方法可以在编译时完成比较。此外,给出的示例纯粹是对传递给编译器的额外信息的演示。你有关于特质问题的答案吗?
  • 通过在给定函数体的情况下将其作为模板参数,您不会获得更多的编译时信息。如果另一个参数在编译时已知,则函数的结果可以在编译时使用。这就是constexpr 的工作原理。我的模板类型参数是指使用 bitwise_and_operator&lt;Flags&gt; 而不是让它推断类型。在可能的情况下,应该首选类型推导,而不是为它做编译器的工作。如果Flagged 更改为只有类型作为模板参数,HasOne 也可以去掉它的Flags 模板参数。
  • 克里斯感谢您的回答,但如果我明确想让编译器工作怎么办?我喜欢依靠编译器为我完成工作,但直接指定方法可能会有优势。但是,是的,我们可以制作一些更通用的更高级的操作符版本。无论哪种方式,我仍然希望有一种方法可以根据枚举值确定枚举类型并在上面的示例中创建请求的方法。
  • 我看不到逻辑。您更喜欢将类型显式地赋予可以推断它的函数,例如bitwise_and_operator&lt;Flags&gt;,但您更喜欢编译器推断类型以执行Flagged&lt;Flags::One&gt;(...) 而不是Flagged&lt;Flags, Flags::One&gt;。是的,在这里说两次Flags 很烦人。在已经将Flags 指定为每个参数的类型之后,再次为bitwise_and_operator 调用说Flags。这同样是多余的。有一天,你会做编译器的工作,结果却弄错了。一个流行的例子是for (const pair&lt;K, V&gt; &amp;p : map),它复制每一对。

标签: c++ templates enums


【解决方案1】:

你有什么理由想要enum_value 作为模板参数?您可以简单地将其作为另一个参数传递:

template <typename enum_type>
constexpr bool Flagged(enum_type src, enum_type flag) {
    return (src & flag) == flag;
}

// Has flag one?
constexpr bool HasOne(Flags flags) {
    return Flagged(flags, Flags::One);
};

【讨论】:

  • 谢谢巴里。我相信我们可以使用 constexpr 使用 normal 函数定义来生成类似的代码,但是直接指定编译时间信息有一些优势。 Flagged<:one>(flags) 明确说明了哪些信息是编译时间,哪些信息是在运行时打开的(标志)。这可能很有用。
【解决方案2】:

到目前为止,只有一个宏:

 #define FLAGGED(x,y) Flagged<decltype(x),x>(y)

有一个proposal in the works 来解决这个问题。

【讨论】:

  • 感谢您提供链接。
猜你喜欢
  • 2018-10-18
  • 2019-01-05
  • 1970-01-01
  • 2013-03-13
  • 1970-01-01
  • 2021-08-05
  • 2017-01-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多