支撑函数转换为引用类型,标准中的漏洞或编译器错误?

Braced functional cast to reference type, a hole in the standard or compilers bug?

根据标准,花括号函数转换总是产生纯右值,[expr.cast]/2

Otherwise, the expression is a prvalue of the specified type whose result object is direct-initialized with the initializer.

指定类型是引用类型时很难解释,因为它可能发生在泛型编程中。编译器在这种情况下采用了特定的行为:

#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&>);
}

对于 Clang,GCC 和 MSVC 同意 decltype(T{a}) 其中 T is A&A& 类型这一事实。这意味着根据 decltype 规范,结果不是纯右值。所以看起来 none 这些编译器符合标准。

T{a}对Clang和MSVC的评估只是直接引用绑定。

GCC 拒绝编译 g1。表达式 T{a} 构造了 a 的副本,然后暂时将临时绑定到 T{a} 的结果(这可以在模板 h [=21 的显式实例化的汇编中看到) =]).

在这种情况下有编译器吗?还是只是 "no diagnostic required" 个案例?

这是CWG1521:

T{expr} with reference types

According 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.

这个措辞不处理 T 是引用类型的情况:不可能创建该类型的临时对象,并且可能结果是一个 xvalue,而不是 prvalue。