【问题标题】:constexpr vs const vs constexpr constconstexpr vs const vs constexpr const
【发布时间】:2016-07-24 03:57:47
【问题描述】:

const-vs-constexpr-on-variables

这家伙关于 constexpr 的说法是正确的 if double 被使用(或 float 当然)。但是,如果您将 var 类型从 double 更改为整数类型,如 int、char 等,则一切正常。为什么会这样?

http://ideone.com/DAWABE

int main() 
{
    const int PI1 = 3;
    constexpr int PI2 = 3;
    constexpr int PI3 = PI1;  // works
    static_assert(PI1 == 3, "");  // works

    const double PI1__ = 3.0;
    constexpr double PI2__ = 3.0;
    constexpr double PI3__ = PI1__;  // error
    static_assert(PI1__ == 3.0, "");  // error
    return 0;
}

Update:下面这行写错了,我的意思是PI3__ = PI1__

constexpr double PI3__ = PI1;  // I meant PI1__

问题:

  1. 为什么const int = 3 是编译时间常数而const double = 3.0 不是?

  2. 有什么理由我应该使用constexpr const int val; 而不是constexpr int val?他们似乎都做同样的事情。

【问题讨论】:

  • 您使用哪种编译器? static_assert(PI1__ == 3, ""); 不允许 sinc PI1__ 不是编译时常量。
  • @HelloWorld 我知道这行不通。我的问题是为什么将其更改为 int 使其工作。我正在使用 GCC 5.1 和 VS 2015 Update 2。
  • 因为按照标准 const int 是编译时间常数,但 const double 不是。
  • @SergeyA 标准在哪里这么说。这就是我感到困惑的部分。为什么 const int 是编译时间常数而 const double 不是,这在我看来没有意义。
  • @Phantom,在答案中回答。

标签: c++ c++14 constexpr


【解决方案1】:

根据您在评论中的回答,这是我的回答。 C++ 标准说得很清楚。不过 GCC 5.1 在这里工作得很好:https://godbolt.org/g/2oV6Hk

类型 T 的转换常量表达式是隐式转换为类型 T 的表达式,其中转换后的 expression 是一个常量表达式,隐式转换序列仅包含 § 5.20 134 c ISO/IEC N4567

[...]

(4.6) — 积分促销 (4.5),

(4.7) — 整数转换 (4.7) 而非窄化转换 (8.5.4),

[...]

关于 n4567 中缩小转换 (8.5.4/7) 的参考:

窄化转换是隐式转换

  • 从浮点类型到整数类型,或
  • 从long double到double或者float,或者从double到float,除非源是常量表达式并且转换后的实际值在可以表示的值范围内(即使不能准确表示) , 或
  • 从整数类型或无作用域枚举类型到浮点类型,除非源是常量表达式并且转换后的实际值将适合目标类型并且在转换回原始值时将产生原始值输入,或
  • 从整数类型或无作用域枚举类型到不能表示原始类型的所有值的整数类型,除非源是常量表达式并且转换后的实际值将适合目标类型并生成转换回原始类型时的原始值。

【讨论】:

  • 我的意思是PI3__ = PI1__,而不是PI3__ = P1。我已经更新了我的问题。我猜的问题是为什么 const int 是编译时间常数,而 const double 不是编译时间常数。
【解决方案2】:

从 cmets 看来,OP 要求标准报价,将 const int 定义为编译时常量,但 const double 不是。

对应的细节在5.19,Constant Expressions。特别是:

...左值到右值的转换 (4.1),除非它应用于 整数或枚举类型的非易失性左值,它指的是 具有先前初始化的非易失性 const 对象,已初始化 使用常量表达式...

int 是整数类型,而double 不是。

【讨论】:

    【解决方案3】:

    编译器不允许在初始化 constexpr 变量期间进行隐式缩小或非整数提升。

    这将起作用:

    int main()
    {
        const int PI1 = 3;
        constexpr int PI2 = 3;
        constexpr int PI3 = PI1;  // works
        static_assert(PI1 == 3, "");  // works
    
        const double PI1__ = 3;
        constexpr double PI2__ = 3;
        constexpr double PI3__ = double(PI1);  // works with explicit cast
        static_assert(PI2__ == 3, "");  // works now. PI1__ isn't constexpr
        return 0;
    }
    

    【讨论】:

    • 缩小发生在哪里?
    • PI1 是一个整数。 PI3__ 是双重的。
    • @SergeyA 实际上,HelloWorld 是对的。这是一个非整体促销。没有缩小..
    • @Phantom 该链接末尾的代码与我的不同。我从 OP 发布的内容中获取了代码。这与他的链接指向的不同。
    猜你喜欢
    • 2012-11-01
    • 1970-01-01
    • 2015-05-04
    • 2023-03-15
    • 2015-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多