c++ - constexpr(但不是真的)构造函数在 gcc 中编译但在 clang 中不编译

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

我在 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 上)。

最佳答案

gcc 和 clang 都是正确的,您的程序格式错误,无需诊断,因为无法调用构造函数,因此无法将它们评估为核心常量表达式的子表达式。

来自 [dcl.constexpr]p5 :

For a non-template, non-defaulted constexpr function or a non-template, non-defaulted, non-inheriting constexpr constructor, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression ([expr.const]), the program is ill-formed; no diagnostic required. [ Example:

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
};

— end example ]

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

{ constexpr A a; }

关于c++ - constexpr(但不是真的)构造函数在 gcc 中编译但在 clang 中不编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48936879/

相关文章:

c++ - 使用 -march 编译会导致线程显示 "pure virtual method called"

c - 在 gcc 命令中添加 linux 头文件

c++ - 'static void' 作为 decl-specifier

c++ - 在 Mac OS 10.6 上使用 boost::xpressive 编译时间过长

c++ - 在 “function name” 运算符后面键入参数 <T>

c - 重定位二进制代码时出错(gcc -> objdata -> 加载二进制代码 -> 并执行)

ios - 如何在iOS上为Clang生成链接映射文件?

c++ - 列出所有物理驱动器 (Windows)

c++ - 通过cmake禁用特定库的警告

objective-c - 每个文件都是用 Objective-C 编译的吗?