【问题标题】:convert strongly typed enumerator to its underlying type in compilation time?在编译时将强类型枚举器转换为其基础类型?
【发布时间】:2018-08-08 01:38:33
【问题描述】:

我了解强类型枚举器可以转换为其基础类型:

template<typename E> constexpr 
auto to_integral(E e) -> typename std::underlying_type<E>::type
{
    return static_cast<typename std::underlying_type<E>::type>(e);
}

但是,这是在运行时工作的。

既然枚举器在编译时已经存在,有没有办法在编译时进行这种转换?

【问题讨论】:

  • “但是,这是在运行时工作的。”你为什么这么认为?
  • @cpplearner 这是一个函数调用,函数调用在运行时工作,对吧?
  • 该标准根本没有“编译时间”的概念,因此它不能保证任何事情。它有一个“常量表达式”的概念。
  • IMO 如果编译器不优化该调用完全它不会优化任何东西。
  • 我在 Godbolt 上玩过你的样本。为此,我添加了第二个to_integral_rt() 没有constexpr(以查看差异)。 gcc 8.1 --std=c++17const int i = to_integral(E::E123); 编译一个mov,为非constexpr 风格编译一个mov call to_integral_rt() mov。但是,添加-O2 两个调用都被优化掉了——两个常量都直接设置到输出命令中。 (我希望像过去那样摆弄类似的事情。)Live Demo on godbolt

标签: c++ c++11 strongly-typed-enum


【解决方案1】:

正如下面链接中提到的草药萨特,

When does a constexpr function get evaluated at compile time?

constexpr 函数将在编译时计算,当它的所有参数都是常量表达式并且结果也用于常量表达式时。常量表达式可以是文字(如 42)、非类型模板参数(如模板类数组中的 N;)、enum 元素声明(如枚举 Color { Red, Blue, Green }; 中的 Blue),另一个变量声明为 constexpr,等等。

当所有参数都是常量表达式并且结果未在常量表达式中使用时,它们可能会被计算,但这取决于实现。

【讨论】:

    【解决方案2】:

    你写的函数可以在编译时使用。

    template<typename E> constexpr 
    auto to_integral(E e) -> typename std::underlying_type<E>::type
    {
        return static_cast<typename> std::underlying_type<E>::type>(e);
    }
    
    enum class A : int { a };
    static_assert(to_integral(A::a) == 0);
    

    这应该可以编译,表明该函数可以在编译时运行。 但是,constexpr 函数仅表明该函数符合编译时要执行的所有要求。要强制执行此计算(即使在 -O0 时),您需要使变量也为 constexpr。

     constexpr auto i = to_integral(A::a);
     i = 42;
    

    对于一个变量,constexpr 简单的意思是:在编译时初始化。之后,您可以像运行时一样使用它。

    在上面的示例中,我确信大多数编译器都会优化代码,而不管 constexpr 关键字如何。 (给定 -O2 或 -O3)但是,如果代码变得更复杂,则需要 constexpr 来强制它们对其进行优化,而不考虑成本。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-13
      • 1970-01-01
      • 2018-07-04
      • 1970-01-01
      • 2022-01-07
      • 1970-01-01
      • 2016-11-30
      相关资源
      最近更新 更多