10

在以下结构定义中,构造函数A(int)将其工作委托给立即函数构造函数A()

struct A {       
    int i = 0;
    consteval A() = default;
    A(int) : A() {}
};

Clang 接受它,但没有 GCC 抱怨:

error: 'this' is not a constant expression

和 MSVC:

'A::A': call to immediate function is not a constant expression

演示:https ://gcc.godbolt.org/z/7e3fWzYzr

哪个编译器是正确的?

4

2 回答 2

1

我认为应该接受这样的非 constexpr 构造函数,因为 gcc 已经接受了以下代码。

struct Foo {
    int a = 0;
    
    consteval Foo() = default;
    
    static consteval Foo make_foo() noexcept { return Foo{}; }
    
    // Foo(iny) : Foo() {}
    Foo(int) : Foo(make_foo()) {}
};

int main()
{
    static_cast<void>(Foo{42});
}

我想这也是 C++ 标准中的一个错误,似乎由问题CWG2410跟踪。

IMO 当前未正确指定 consteval 构造函数调用,因为在 C++ 中,构造函数调用本身绝不是表达式,因此不应被视为常量表达式。

于 2022-02-17T11:03:53.730 回答
0

如您所知,this是所有非静态成员函数的参数。参数永远不是常量表达式。所以this不能用在常量表达式中。

当您初始化非静态成员变量时,例如:

int i = 0;

此初始化将在运行时进行。不要认为你的空 ( defaulted) 构造函数什么都不做。它实际上必须i在运行时初始化为零。但是编译器应该如何生成一个consteval执行运行时任务的函数(如您的默认 ctor)?这只是一个矛盾。

让我向您展示一个类似的场景:

consteval int multiply( const int op1, const int op2 )
{
    return op1 * op2;
}

int main( )
{
    constexpr int op1 { 2 };
    constexpr int op2 { 3 };
    std::cout << multiply( op1, op2 ) << '\n'; // compiles for obvious reasons

    int op3 { 2 };
    int op4 { 3 };
    std::cout << multiply( op3, op4 ) << '\n'; // doesn't compile
}

和:

test.cpp: In function 'int main()':
test.cpp:57:32: error: the value of 'op3' is not usable in a constant expression
   57 |         std::cout << multiply( op3, op4 ) << '\n';
      |                                ^~~
test.cpp:55:13: note: 'int op3' is not const
   55 |         int op3 { 2 };
      |             ^~~

在第一次调用中,consteval函数正在接收constexpr参数。所以很开心。
在第二次调用中,它接收非constexpr参数。
this因为你的constevalctor 会导致类似的情况:

test.cpp: In constructor 'A::A(int)':
test.cpp:41:22: error: 'this' is not a constant expression
   41 |         A( int ) : A() { }
      |                      ^
于 2022-01-12T08:58:07.677 回答