'Can `consteval` delegating constructor be called from an ordinary constructor?
In the following struct definition, the constructor A(int) delegates its work to immediate-function constructor A():
struct A {
int i = 0;
consteval A() = default;
A(int) : A() {}
};
Clang accepts it, but not GCC complaining:
error: 'this' is not a constant expression
and MSVC:
'A::A': call to immediate function is not a constant expression
Demo: https://gcc.godbolt.org/z/7e3fWzYzr
Which compiler is correct?
Solution 1:[1]
I think such non-constexpr constructor should be accepted, as gcc has already been accepting the following code.
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});
}
I guess this is also a bug in the C++ standard, seems tracked by the issue CWG2410.
IMO currently consteval constructor calls are not specified correctly, because in C++ a constructor call is never itself an expression, and hence shouldn't be considered as a constant expression.
Solution 2:[2]
As you know, this is a parameter to all non-static member functions. And parameters are never constant expressions. So this can't be used in a constant expression.
When you initialize the non-static member variable like:
int i = 0;
this initialization will take place at run-time. And don't think that your empty (defaulted) constructor is doing nothing. It actually will have to initialize i with zero at run-time. But how is the compiler supposed to generate a consteval function (like your default ctor) which does run-time tasks?! It's just a contradiction.
Let me show you a similar scenario:
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
}
And:
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 };
| ^~~
In the 1st call, the consteval function is receiving constexpr arguments. So it's happy.
In the 2nd call, it's receiving non-constexpr arguments.this for your consteval ctor causes a similiar condition:
test.cpp: In constructor 'A::A(int)':
test.cpp:41:22: error: 'this' is not a constant expression
41 | A( int ) : A() { }
| ^
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | F.v.S. |
| Solution 2 | digito_evo |
