【问题标题】:constexpr (but not really) constructor compiles in gcc but not in clangconstexpr(但不是真的)构造函数在 gcc 中编译,但在 clang 中不编译
【发布时间】:2018-08-02 20:41:31
【问题描述】:

我在使用 C++14 及更高版本的 constexpr 构造函数时发现了一些奇怪的东西。这是我的代码:

#include <iostream>
#include <string>

using std::cout;
using std::endl;

#define PFN(x) cout << x << __PRETTY_FUNCTION__ << endl
#define PF     PFN("")
#define NL     cout << endl

struct A {
    constexpr A() { PF; }
    virtual ~A() { PF; NL; }
};

struct B : A {
    constexpr B() { PFN(" "); }
    virtual ~B() { PFN(" "); }
};

int main(int argc, char** argv) {
    { A a; }
    { B b; }
    A* a = new B;
    delete a;
    return 0;
}

足够简单的例子。我用g++ -std=c++14 -o cx_test cx_test.cpp 编译它,期望它给我一个编译错误(因为我使用cout 和流运算符来打印函数的名称。但是,令我惊讶的是,它编译了!当我运行它时,它给出了以下输出:

$> g++ -std=c++14 -o cx_test cx_test.cpp && ./cx_test
constexpr A::A()
virtual A::~A()

constexpr A::A()
 constexpr B::B()
 virtual B::~B()
virtual A::~A()

constexpr A::A()
 constexpr B::B()
 virtual B::~B()
virtual A::~A()
$>

但是,当我用 clang 编译时,我得到:

$> clang++ -std=c++14 -o cx_test cx_test.cpp && ./cx_test
cx_test.cpp:12:15: error: constexpr constructor never produces a constant expression [-Winvalid-constexpr]
    constexpr A() { PF; }
              ^
cx_test.cpp:12:21: note: non-constexpr function 'operator<<<std::char_traits<char> >' cannot be used in a constant expression
    constexpr A() { PF; }
                    ^
cx_test.cpp:9:12: note: expanded from macro 'PF'
#define PF PFN("")
           ^
cx_test.cpp:8:26: note: expanded from macro 'PFN'
#define PFN(x) cout << x << __PRETTY_FUNCTION__ << endl
                         ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/ostream:556:5: note: declared here
    operator<<(basic_ostream<char, _Traits>& __out, const char* __s)
    ^
1 error generated.
$>

这似乎是 g++ 的一个错误,因为构造函数似乎违反了constexpr 的限制,但我不太确定。哪个编译器是正确的?

Here 是 g++ 版本,here 是 clang 版本(在 ideone 上)。

【问题讨论】:

  • 可能与this one 相关,您是否尝试过-fno-builtin ... operator &lt;&lt; 不是constexpr,但它可能会被折叠成内置函数。
  • -fno-builtin 不会影响任何一个。关于另一个问题,我不确定 c++14 和 c++17 中对 constexpr 的宽松要求是否会影响接受的答案。
  • 它们都是正确的......我上面链接的答案解释了为什么这是不正确的不需要诊断......你不会强迫它们在常量表达式上下文中使用see modified version where gcc generates an error当你强制它在常量表达式上下文中使用时。
  • 如果您想要 C++14 特定的引用,请参阅 this question,它涵盖了类似的基础并提供了 C++14 的相同细节。

标签: c++ gcc clang c++14 constexpr


【解决方案1】:

gcc 和 clang 都是正确的,您的程序格式不正确,不需要诊断,因为无法调用构造函数以便它们可以作为核心常量表达式的子表达式进行评估。

来自[dcl.constexpr]p5

对于非模板、非默认的 constexpr 函数或 非模板,非默认,非继承 constexpr 构造函数,if 不存在任何参数值,因此调用函数或 构造函数可以是核心常量的求值子表达式 表达式 ([expr.const]),程序格式错误;没有诊断 必需。 [ 例子:

constexpr int f(bool b)
  { return b ? throw 0 : 0; }               // OK
constexpr int f() { return f(true); }       // ill-formed, no diagnostic required

struct B {
  constexpr B(int x) : i(0) { }             // x is unused
  int i;
};

int global;

struct D : B {
  constexpr D() : B(global) { }             // ill-formed, no diagnostic required
                                            // lvalue-to-rvalue conversion on non-constant global
};

—结束示例]

如果我们强制在常量表达式上下文中评估构造函数,那么您也会收到来自 gcc 的诊断 (see it live):

{ constexpr A a; }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-18
    • 1970-01-01
    • 2017-10-12
    • 2023-01-05
    • 2020-06-03
    • 1970-01-01
    相关资源
    最近更新 更多