Consider the code below:
#include <cstdio>
struct A
{
A(){}
explicit A(const A&) {std::puts("copy");}
};
int main()
{
A a;
true ? a : A();
return 0;
}
As I understand the ternary would try to copy a and should fail since the copy constructor is explicit, however gcc compiles this just fine and creates a copy. Clang spits out an error as expected.
Is this a bug in gcc?
I'm using gcc 8.1 and clang 7.0, in c++17 mode, but I also tried all versions of gcc in compiler explorer in c++98 mode, and they all behave the same.
Clang is right to reject it, and it is indeed a GCC bug. I'll quote n4659 (closest document I have to to the C++17 standard) for simplicity.
First and foremost, the type of of the conditional expression in your example, as specified by [expr.cond] ¶6 must be a prvalue of type A
.
Now, according to [expr.cond] ¶7, emphasis mine:
Lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard conversions are performed on the second and third operands.
a
must be able to undergo the lvalue-to-rvalue conversion. Which for a
is specified in [conv.lval] ¶3.2 (again, emphasis mine) as
Otherwise, if T has a class type, the conversion copy-initializes the result object from the glvalue.
Copy initialization of an A
from an A
, in any context, should pick a converting constructor in overload resolution ([over.match.copy] ¶1.1):
The converting constructors of T are candidate functions.
And an explicit copy constructor is not a converting constructor ([class.conv.ctor] ¶3)
A non-explicit copy/move constructor ([class.copy]) is a converting constructor.
A conforming C++ implementation cannot accept the conditional expression your wrote as well-formed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With