花括号初始化 vs. 圆括号错误

8

我正在为GCC提交一个bug,但我想再次确认一下。

考虑以下程序:

#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及以上版本接受第一个程序但拒绝第二个,声称“将类型为'int'的rvalue表达式无效转换为类型'int&'”。这是GCC的一个错误吗?还是这确实是上述情况下{}和()之间的区别(因此是Clang和MSVC的错误)?
编辑:问题可以缩小到以下简单摘录:
int i; (int&){i};

并且

int i; (int&)(i);

你能定义和初始化一个未命名的左值引用吗?无论如何,这个错误似乎是不正确的。 - krzaq
4
这是核心问题1288。GCC应该正在实现它的解决方案,但可能还没有完全修复。 - T.C.
3
尽管T{x}没有明确定义,请参见核心问题1521 - T.C.
2
@T.C.:发现得不错。看起来对回答很有帮助。 - GManNickG
@T.C. 想写个回答让我点赞吗? - Barry
显示剩余3条评论
1个回答

6

有两个独立的问题:

  • 标准不清楚对于引用类型T,T{x}应该做什么。目前[expr.type.conv]/1表示它创建了一个类型为T的prvalue,这对于引用类型来说是无意义的。这是core issue 1521
  • 可能的合理方法是对于引用类型TT{x}大致执行T __tmp{x};,然后产生相当于static_cast<T>(__tmp)的结果(因此xvalue用于rvalue引用T,lvalue用于lvalue引用T)。然而,C++11发布时出现了列表初始化引用的规范错误,使其始终创建临时对象。结果是int i; int &r{i};无法编译,因为它会尝试将r绑定到i的临时副本,这显然是无意义的。这是由core issue 1288修复的,GCC应该实现它,但从错误消息看来似乎没有完全解决。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接