大括号初始化vs.括号错误



我正在为此提交一个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应该实现其解决方案,但从错误消息中看起来它没有完全修复。

最新更新