According to the standard, a braced functional cast always results in a prvalue, [expr.cast]/2
Otherwise, the expression is a prvalue of the specified type whose result object is direct-initialized with the initializer.
Which is hard to interpret when the specified type is a reference type, as it may happen in generic programming. Compiler have adopted specific behavior in this case:
#include <type_traits>
struct A {
A ()=default;
A (const A&);
};
template <class T, class U>
decltype(auto)
f(U& a) {
static_assert (std::is_same_v <decltype (T{a}), T>);
return T{a};
}
#if defined(__clang__) || defined(_MSC_VER)
void g1(A a){
decltype(auto) v = f<A&>(a); //GCC: error try to bind a prvalue to a non-const lvalue
static_assert (std::is_same_v <decltype(v), A&>);
}
#endif
void g2(A a){
decltype(auto) v = f<const A&>(a); //GCC: call the copy constructor of A
//MSVC and Clang: a no op (direct reference binding)
static_assert (std::is_same_v <decltype(v), const A&>);
}
For Clang, GCC and MSVC agree on the fact the decltype(T{a})
where T is A&
is of type A&
. Which means the result is not a prvalue according to decltype specification. So it looks that none of these compilers is standard compliant.
The evaluation of T{a}
for Clang and MSVC is just a direct reference binding.
GCC refuses to compiles g1
. The expression T{a}
construct a copy of a
and the temporary is then tentatively bound to the result of T{a}
(this can be seen in the assembly of the explicit instantiation of template h here).
Is any compiler right in such a situation? Or is it just a "no diagnostic required" case?
This is CWG1521:
T{expr}
with reference typesAccording to 8.2.3 [expr.type.conv] paragraph 4,
Similarly, a simple-type-specifier or typename-specifier followed by a braced-init-list creates a temporary object of the specified type direct-list-initialized (11.6.4 [dcl.init.list]) with the specified braced-init-list, and its value is that temporary object as a prvalue.
This wording does not handle the case where
T
is a reference type: it is not possible to create a temporary object of that type, and presumably the result would be an xvalue, not a prvalue.
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