Clang is correct. It works in g++ because it's automatically eliding the Copy constructor (RVO). if you pass -fno-elide-constructors
. g++ will also complain.
The C++14 standard isn't clear about Copy-Elision in constexpr
objects..
[class.copy/32] ...(partially reproduced here)
When the criteria for elision of a copy/move operation are met.... .... the selected constructor must be accessible even if the call is
elided.
Until we know the definition of accessible
? We can assume g++ is also correct?
dcl.constexpr/9
A constexpr specifier used in an object declaration declares the
object as const. Such an object shall have literal type and shall be
initialized. If it is initialized by a constructor call, that call
shall be a constant expression ([expr.const]). Otherwise, or if a
constexpr specifier is used in a reference declaration, every
full-expression that appears in its initializer shall be a constant
expression.
Dietmar Kuhl's answer tells us what's ahead.
Demo:
struct Wrapper {
int value;
constexpr explicit Wrapper(int v) noexcept : value(v) {}
Wrapper(const Wrapper& that) noexcept : value(that.value) {}
};
constexpr Wrapper makeWrapper(int v)
{
return Wrapper(v);
}
int main()
{
constexpr auto x = makeWrapper(123);
}
Compile with
g++ -std=c++14 -Wall -pedantic -fno-elide-constructors main.cpp && ./a.out
See it live here