Tri*_*dle 13 c++ conditional-operator rvalue-reference c++11 universal-reference
以下定义了一个min函数
template <typename T, typename U>
constexpr auto
min(T&& t, U&& u) -> decltype(t < u ? t : u)
{
return t < u ? t : u;
}
Run Code Online (Sandbox Code Playgroud)
有一个问题:它似乎写得完全合法
min(10, 20) = 0;
Run Code Online (Sandbox Code Playgroud)
这已经过Clang 3.5和g ++ 4.9的测试.
解决方案很简单,只是std::forward用来恢复参数的"rvalue-ness",即修改正文和decltype说
t < u ? std::forward<T>(t) : std::forward<U>(u)
Run Code Online (Sandbox Code Playgroud)
但是,我无法解释为什么第一个定义不会产生错误.
鉴于我的转发和普遍引用,两者的理解t和u演绎他们的论据类型,int&&当传递整数常量.但是,在正文中min,参数有名称,因此它们是左值.现在,条件运算符的真正复杂规则发挥作用,但我认为相关的是:
- E2 [和] E3都是相同类型的glvalues.在这种情况下,结果具有相同的类型和值类别.
因此,返回类型operator?:应该是int&&为好,应该不是吗?但是,(据我所知),Clang和g ++都min(int&&, int&&)返回了左值引用int&,因此允许我分配给结果.
很明显,我的理解存在差距,但我不确定我到底是什么.任何人都可以向我解释这里到底发生了什么吗?
编辑:
正如Niall正确指出的那样,这里的问题不在于条件运算符(它int&&按预期返回类型的左值),而是使用decltype.规则decltype说
如果表达式的值类别是左值,那么decltype指定T&
所以函数的返回值变为int&& &,由C++ 11的引用折叠规则变为普通int&(与我的预期相反int&&).
但是如果我们使用std::forward,我们将operator?:(后面)的第二个和第三个参数转换为rvalues - 特别是xvalues.因为xvalues仍然是glvalues(你在后面保持?),所以应用相同的条件运算符规则,并且我们得到相同类型和值类别的结果:即,int&&它是xvalue.
现在,当函数返回时,它会触发不同的decltype规则:
如果表达式的值类别是xvalue,则decltype指定T &&
这一次,参考折叠给了我们int&& && = int&&,更重要的是,函数返回了一个xvalue.这使得分配给返回值是非法的,就像我们想要的那样.
问题可能在于decltype()规则.
这是暗示; 如果删除了尾随返回类型
template <typename T, typename U>
constexpr auto
min(T&& t, U&& u)
{
return t < u ? t : u;
}
Run Code Online (Sandbox Code Playgroud)
并且允许编译器推导出它,返回类型是int.
使用decltype
decltype ( expression )
...
如果表达式的值类别是左值,则decltype指定T&
取自cppreference.
由于涉及t和的表达式u是左值(它们是左值 - 命名为r值引用),因此返回值是左值引用.
在这种情况下,它会导致可能修改文字的潜在情况.使用"通用引用"(或"转发引用")和相关的引用折叠规则时,需要谨慎使用转发.
正如您已经指出的那样,为了纠正这种情况,正确使用std::forward需求和返回类型将是预期的.
有关详细信息std::forward和参考折叠,请参见此处.
| 归档时间: |
|
| 查看次数: |
899 次 |
| 最近记录: |