将函数转换为引用类型,在标准中存在漏洞还是在编译器中出现错误? [英] Braced functional cast to reference type, a hole in the standard or compilers bug?
问题描述
According to the standard, a braced functional cast always results in a prvalue, [expr.cast]/2
否则,表达式是指定类型的prvalue,其结果对象使用初始化程序直接初始化.
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&>);
}
对于Clang,GCC和MSVC同意以下事实,其中 T是A&
的 decltype(T {a})
属于 A& 代码>.这意味着根据decltype规范,结果不是prvalue.因此,这些编译器似乎都不符合标准.
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.
对Clang和MSVC的 T {a}
的评估仅是直接引用绑定.
The evaluation of T{a}
for Clang and MSVC is just a direct reference binding.
GCC拒绝编译 g1
.表达式 T {a}
构造了 a
的副本,然后临时将临时绑定到 T {a}
的结果上(这可以可以在模板h的显式实例化的汇编中看到此处).
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?
推荐答案
这是 CWG1521 :
T {expr}
以及引用类型
T{expr}
with reference types
根据8.2.3 [expr.type.conv]第4段,
According to 8.2.3 [expr.type.conv] paragraph 4,
类似地,简单类型说明符或类型名称说明符后跟括号初始列表会创建一个临时对象指定类型的直接列表初始化(11.6.4 [dcl.init.list]),带有指定的括号初始化列表,其值是该临时对象作为prvalue.
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.
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.
这篇关于将函数转换为引用类型,在标准中存在漏洞还是在编译器中出现错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!