返回统一的初始化参考是否有效?
此代码示例是否有效?
using ref = char&;
ref foo(ref x) {
return ref{x};
}
int main() {
char a;
foo(a);
return 0;
}
看起来:
gcc 4.9说不
main.cpp: In function 'char& foo(ref)':
main.cpp:4:15: error: invalid cast of an rvalue expression of type 'char' to type 'ref {aka char&}'
return ref{x};
^
http://coliru.stacked-crooked.com/a/cb6604b81083393f
那么哪个编译器是对的? 还是没有指定?
它很容易通过以下方式克服gcc构建错误:
使用括号代替大括号
ref foo(ref x) {
return ref(x);
}
通过命名返回的值
ref foo(ref x) {
ref ret{x};
return ret;
}
选项1.打破统一初始化,选项2.添加无用的代码行。
类似的问题已经在这里提出:为什么我不能在初始化器列表中使用统一初始化来初始化引用?
但是提到的pr50025在gcc 4.9中是固定的。
我知道上面的代码示例是非常没用的,但我过于简单地指出了这个问题。 在现实生活中,代码问题可以隐藏在通用函数中,如:
#include <utility>
template <typename Tp, typename... Us>
Tp bar(Us&&... us) {
return Tp{std::forward<Us>(us)...};
}
这似乎是标准中的一个遗漏,GCC正在执行标准所要求的内容,而铿锵正在实现可能的目标。
从C ++ 11(强调我的):
5.2.3显式类型转换(功能符号)[expr.type.conv]
1一个简单类型说明符(7.1.6.2)或类型名称说明符(14.6),后面跟着一个带括号的表达式列表,根据表达式列表构造一个指定类型的值。 如果表达式列表是单个表达式,那么类型转换表达式与相应的表达式(5.4)是等价的(在定义中,如果定义的话)。 [...]
[...]
3同样地,一个简单型或说明符类型名称说明符后跟一个支撑-INIT-列表中创建具有指定掺进-INIT-列表中指定的类型的直接清单初始化(8.5.4)的临时对象, 并且其值就是那个临时对象作为prvalue 。
对于braced-init-list的情况,标准并没有指定它的作用就像C风格的转换。 它并没有:
typedef char *cp;
int main() {
int i;
(cp(&i)); // okay: C-style casts can be used as reinterpret_cast
(cp{&i}); // error: no implicit conversion from int * to char *
}
不幸的是, T(expr)
等价于(T)expr
也是一个例外,其中一个功能强制转换不一定产生一个prvalue。 该标准未能为使用braced-init-list到引用类型的功能强制类型指定类似的异常。 因此,在你的例子中, ref{x}
构造了一个从{x}
初始化的类型ref
,direct-list的临时类型。 这个临时值被视为一个prvalue,因为这就是标准所说的行为应该是什么,并且这个prvalue不能用于绑定到一个左值引用。
我强烈怀疑,如果这是由ISO C ++委员会提出的,那么标准将会改变为要求clang的行为,但是根据目前的标准措辞,我认为GCC是正确的,至少对于您的具体示例而言。
您可以省略ref
( Tp
)来避免该问题,而不是添加变量或切换到括号。
template <typename Tp, typename... Us>
Tp bar(Us&&... us) {
return {std::forward<Us>(us)...};
}
链接地址: http://www.djcxy.com/p/24479.html
上一篇: Is returning uniform initialized reference valid?
下一篇: Is it a good pattern to raise exceptions in a python decorator?