【发布时间】:2014-03-08 13:09:53
【问题描述】:
在回答 using boost math constants in constexpr 并建议 OP 使用 boost 的模板化函数来处理 constexpr 变量而不是非模板化常量来消除 clang 错误之后,我决定尝试看看什么条件会在 clang 中重现该错误。让我们尝试复制 boost 的宏扩展为:
namespace double_constants{ static const double name = 25; }
static constexpr double SEC3 = double_constants::name;
这会产生以下错误(继续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; }
没关系,我们预料到了。现在将double 更改为int:
namespace double_constants{ static const int name = 25; }
static constexpr double SEC3 = double_constants::name;
没有错误?不用说我很困惑。我认为错误是因为变量被定义为const 而不是constexpr,除非我遗漏了一些东西。一起来看看cppreference:
constexpr 变量必须满足以下要求:
- 必须立即构造或赋值。
- 构造函数参数或要分配的值必须仅包含文字值、constexpr 变量和函数。
如果我们按字面意思来解释,那么 clang 给出错误是有道理的,因为 name 只是 const,而不是 constexpr。显然double 是LiteralType 因为:
std::cout << std::is_literal_type<double>::value;
输出1。那么,如果name 是int 而不是double,为什么clang 会停止抱怨呢?
P.S.:无法在 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;
我可能不会费心在每个可能的排列中应用static 来查看它是否会有所作为,但我怀疑它确实如此。
【问题讨论】: