我正在为此提交一个GCC错误,但我宁愿仔细检查一下。
考虑以下程序:
#include <utility>
template<typename T, typename A>
void F(A&& a) { T(std::forward<A>(a)); } // Note: () syntax.
int main() { int i; F<int&>(i); }
:
#include <utility>
template<typename T, typename A>
void F(A&& a) { T{std::forward<A>(a)}; } // Note: {} syntax.
int main() { int i; F<int&>(i); }
最新的Clang和MSVC编译器接受这两个程序。GCC 5及以上版本接受第一个程序,但拒绝第二个程序,声称invalid cast of an rvalue expression of type 'int' to type 'int&'
。
这是一个GCC bug吗?或者这确实是上述上下文中T{}
和T()
之间的差异(因此是Clang和MSVC中的错误)?
这个问题可以归结为以下几个更简单的摘录:
int i; (int&){i};
和
int i; (int&)(i);
有两个独立的问题:
- 标准没有明确
T{x}
对于参考类型T
应该做什么。目前[expr.type。conv]/1表示它创建了一个类型为T
的右值,这对于引用类型来说是无意义的。这是核心问题1521 同样的事情可能是让
T{x}
对引用类型T
执行大致的T __tmp{x};
,然后产生相当于static_cast<T>(__tmp)
的值(因此右值引用T
的xvalue和左值引用T
的lvalue)。然而,发布的c++ 11搞砸了引用的列表初始化规范,使得它总是创建一个临时对象。结果是int i; int &r{i};
编译失败,因为它试图将r
绑定到i
的临时副本,这显然是没有意义的。这是由核心问题1288修复的,GCC应该实现其解决方案,但从错误消息中看起来它没有完全修复。