constexpr(但不是真正的)构造函数在GCC中编译,而不是在Clang中编译

constexpr (but not really) constructor compiles in gcc but not in clang

本文关键字:编译 GCC Clang constexpr 构造函数      更新时间:2023-10-16

我正在与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的限制,但我不太确定。哪个编译器正确?

这是G 版本,这是Clang版本(在IDEONE上(。

gcc和clang都是正确的,您的程序不需要诊断,因为没有办法调用构造函数,以便可以将它们作为核心的子表达进行评估恒定表达。

来自[dcl.constexpr] p5:

对于非template,非默认的constexpr函数或 非template,非违约,非属性constexpr构造函数,如果 没有参数值,以至于函数的调用或 构造函数可能是核心常数的评估子表达 表达式([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中获得诊断(请参阅IT LIVE(:

{ constexpr A a; }