【问题标题】:Initializing constexpr with const: Different treatment for int and double [duplicate]用 const 初始化 constexpr:int 和 double 的不同处理
【发布时间】:2017-04-29 17:34:11
【问题描述】:

以下代码编译失败live on Ideone

#include <iostream>
using namespace std;

int main() {
    const double kPi = 3.14;
    constexpr double kPi2 = 2.0*kPi;
    cout << kPi2;
}

错误信息是:

prog.cpp: In function 'int main()':
prog.cpp:6:30: error: the value of 'kPi' is not usable in a constant expression
  constexpr double kPi2 = 2.0*kPi;
                              ^
prog.cpp:5:15: note: 'kPi' was not declared 'constexpr'
  const double kPi = 3.14;

constexprit compiles successfully 替换kPiconst 声明。

另一方面,当使用int 代替double 时,看起来就像const plays wellconstexpr

#include <iostream>
using namespace std;

int main() {
    const int k1 = 10;
    constexpr int k2 = 2*k1;
    cout << k2 << '\n';
    return 0;
}

为什么intdouble 在用const 初始化constexpr 时得到不同的处理?
这是 Ideone 编译器中的错误吗?这是 C++ 标准所要求的吗?这是为什么呢?
上面的代码是UB吗?

P.S.我尝试使用 Visual Studio 2015 C++ 编译器,它编译了第一个代码 sn-p(用 const 初始化 constexpr)就好了。

【问题讨论】:

标签: c++ c++11 constants constexpr


【解决方案1】:

对于在编译时计算的 constexpr,在该 constexpr 的初始化中使用的所有内容也必须在编译时可计算。 如果您将某些内容声明为 const,这并不意味着该值将在编译时可用。

采取以下行:

const double dbl = 2.;

标准未指定double 的表示形式,因此操作系统必须处理此问题。因此,当您的程序被操作系统加载时,您的二进制文件中有一个特殊的汇编子例程可以实现这一点。 如果您使用int,则表示由标准指定,因此编译器将知道如何使用它。然而,同样可以通过将double 设为constexpr 来实现,因此编译器将在编译时计算它。在这种情况下,double 也将是 const(你不能在不创建 constexpr 的情况下创建 const)。

所以这会起作用:

constexpr double kPi = 3.14;
constexpr double kPi2 = 2.0*kPi;

如果您使用 int,编译器将在编译时设置该 const 的值,以便 constexpr 起作用。

请记住,在某些情况下,不同的编译器可以将 const 解释为 constexpr 并使其工作。但这不是标准的一部分。

【讨论】:

  • 也许double的表示没有被标准指定,但它必须在编译时被编译器知道;否则你甚至不能拥有constexpr double
【解决方案2】:

Shafik Yaghmour 已经提供了link explaining the background

由于我必须维护必须使用不同标准编译的代码,我使用以下宏:

#if __cplusplus <= 199711L  // lower than C++11
  #define MY_CONST const
#else // C++11 and above
  #define MY_CONST constexpr
#endif

【讨论】:

    【解决方案3】:

    规则:“constexpr 必须在编译时进行评估”。

    让我们看看下面的代码(通用示例);

        const double k1 = size_of_array(); 
    

    k1 是常量,它的初始化器的值是未知的编译时间,但它的初始化器直到 运行时 是已知的,所以 k1 不是常量表达式。因此,一个 const 变量不是 constexpr。

    但是编译器看到这些代码:

        const int k1 = 10;  
        constexpr int k2 = 2*k1;
    

    出现一个异常。 constexpr 整数值可用于需要 const 整数的任何地方,例如在模板参数和数组声明中 [1]

    您可以从以下链接获得更多信息:

    1. Constexpr - Generalized Constant Expressions in C++11
    2. const vs constexpr on variables | stackoverflow
    3. Difference between constexpr and const | stackoverflow

    【讨论】:

    • 这没有回答问题,这是关于const double k1 = 3.14; 而不是const double k1 = size_of_array();
    • 当然 double k1 = size_of_array(); 不包括问题,但我给出了示例 compile timeruntime initialization 关于 const 值。这个例子是关于每个 const 变量而不是 constexpr (常量表达式)。并在此给定信息之后回答此问题: constexpr 整数值可以在需要 const 整数的任何地方使用,例如在模板参数和数组声明中。MSDN
    • 这个问题是关于值的编译时初始化,与运行时初始化的示例无关。您的回答使 OP 代码的问题似乎是运行时初始化。
    • @M.M 但可能是 usingconst double 而不是 constexpr double 告诉编译器它可以在运行时而不是编译时初始化。这在某些平台上可能是必需的。
    猜你喜欢
    • 2010-10-31
    • 1970-01-01
    • 2010-12-14
    • 1970-01-01
    • 2016-05-10
    • 1970-01-01
    • 1970-01-01
    • 2016-02-18
    • 1970-01-01
    相关资源
    最近更新 更多