在使用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.显然double是LiteralType因为:
std::cout << std::is_literal_type<double>::value;
Run Code Online (Sandbox Code Playgroud)
输出1.那么,为什么抱怨铛停止,如果name是int与不是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规则.请参阅:
尝试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)
然后它应该工作.