clang 3.5 constexpr inconsistency - 使用double但不是int时出错

8 c++ clang constexpr c++11

使用constexpr中的boost数学常量并建议OP使用boost的模板函数constexpr而不是非模板化常量来平息clang错误后,我决定尝试查看哪些条件会重现clang中的错误.让我们尝试复制boost的宏扩展到:

namespace double_constants{ static const double name = 25; }

static constexpr double SEC3 = double_constants::name;
Run Code Online (Sandbox Code Playgroud)

这给出了以下错误(跟随Coliru)

clang++ -std=c++1y -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp:5:25: error: constexpr variable 'SEC3' must be initialized by a constant expression
static constexpr double SEC3 = double_constants::name;
                        ^      ~~~~~~~~~~~~~~~~~~~~~~
main.cpp:5:32: note: read of non-constexpr variable 'name' is not allowed in a constant expression
static constexpr double SEC3 = double_constants::name;
                               ^
main.cpp:3:49: note: declared here
namespace double_constants{ static const double name = 25; }
Run Code Online (Sandbox Code Playgroud)

那没关系,我们期待的.现在double改为int:

namespace double_constants{ static const int name = 25; }
static constexpr double SEC3 = double_constants::name;
Run Code Online (Sandbox Code Playgroud)

没错误?不用说我很困惑.我假设错误是因为变量被定义为const而不是constexpr,除非我遗漏了一些东西.我们来看看cppreference:

constexpr变量必须满足以下要求:

  • 它必须立即构建或赋值.
  • 构造函数参数或要分配的值必须仅包含文字值,constexpr变量和函数.

如果我们要从字面上解释这一点,那么clang在给出错误时是合理的,因为name只是const,而不是constexpr.显然doubleLiteralType因为:

std::cout << std::is_literal_type<double>::value;
Run Code Online (Sandbox Code Playgroud)

输出1.那么,为什么抱怨铛停止,如果nameint与不是double

PS:无法在gcc上重现.


为了澄清,static关键字与问题正交.那就是namespace.根据我的理解,boost宏不会将static const变量包装在类中,而是包含在namespace.我把它缩小到这四种情况:

// Does not compile
const double name = 25;
constexpr int SEC3 = name;

const double name = 25;
constexpr double SEC3 = name;

// Compiles
const int name = 25;
constexpr double SEC3 = name;

const int name = 25;
constexpr int SEC3 = name;
Run Code Online (Sandbox Code Playgroud)

我不太可能不愿意static在每一种可能的情况下应用,看看它是否有所作为,但我怀疑它是否有效.

小智 6

这不是一个错误.不幸的是,C++标准对浮点类型和整数类型有不同的静态/非静态const规则.请参阅:

为什么不允许使用静态const浮点数?

尝试constexpr而不是const,如:

namespace double_constants{ constexpr double name = 25; }
Run Code Online (Sandbox Code Playgroud)

和:

constexpr double name = 25;
constexpr int SEC3 = name;
Run Code Online (Sandbox Code Playgroud)

然后它应该工作.