【问题标题】:clang 3.5 constexpr inconsistency - errors when using double but not intclang 3.5 constexpr 不一致 - 使用 double 但不是 int 时出错
【发布时间】: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。显然doubleLiteralType 因为:

std::cout << std::is_literal_type<double>::value;

输出1。那么,如果nameint 而不是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 来查看它是否会有所作为,但我怀疑它确实如此。

【问题讨论】:

    标签: c++ c++11 clang constexpr


    【解决方案1】:

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

    Why aren't static const floats allowed?

    尝试用 constexpr 代替 const,如下所示:

    namespace double_constants{ constexpr double name = 25; }
    

    和:

    constexpr double name = 25;
    constexpr int SEC3 = name;
    

    那么它应该可以工作了。

    【讨论】:

    • 语句 {static const double name = 25;} 将在内存中生成一个只能在运行时解析的浮点变量。因此,您不能将其分配给需要在编译时解析的 constexpr。但是 {static const int name = 25;} 生成一个可以在编译或运行时解析的变量。因此允许分配给 constexpr。实际上 gcc 有 bug,而不是 clang。
    • static 确实对类产生了影响,如 class A { static const int name = 32; };将编译但 class A { static const double name = 32; };不会。
    猜你喜欢
    • 2022-10-18
    • 2017-10-12
    • 2020-02-19
    • 2015-12-25
    • 1970-01-01
    • 2013-07-12
    • 2012-08-17
    • 1970-01-01
    相关资源
    最近更新 更多