折叠转发引用
Collapsing of forwarding references
给定代码
struct S{};
template <typename T>
auto foo(T&& t)
{
static_assert(std::is_same_v<T, std::remove_cvref_t<T>>);
}
void test()
{
const S s;
foo(s); // error
foo(S{});
S s2;
foo(s2); // error
}
T
将推导为
S const&
S
S&
为什么T
不推导为
S const
S
S
为什么 T
在左值情况下保留引用而不在右值情况下?
转发引用的一个怪癖是你永远不会“只有一个值”。
当T
推导为S
时,这只是因为函数实际上接受S&&
。
当您传递局部变量时,类型推导会识别出这些是左值,因此它将它们绑定到常规引用。在 const S s
的情况下 const
一个。函数签名“改变”以反映这一点。
您将拥有 (const S&)&&
,标准指示折叠为仅 const S&
,然后您将拥有 (S&)&&
,其折叠为仅 S&
,每个引用折叠的规则。
See for yourself(现场演示)
就是这样 forwarding reference works in template argument deduction:
(强调我的)
4) If P is an rvalue reference to a cv-unqualified template parameter (so-called forwarding reference), and the corresponding function call argument is an lvalue, the type lvalue reference to A is used in place of A for deduction (Note: this is the basis for the action of std::forward
这意味着,如果传递了一个左值,T
将被推导为左值引用。否则,如果T
在转发引用中被推导为左值和右值的相同类型,则无法使用std::forward
再次执行完美转发;即当传递左值时作为左值转发,当传递右值时作为右值转发。
给定代码
struct S{};
template <typename T>
auto foo(T&& t)
{
static_assert(std::is_same_v<T, std::remove_cvref_t<T>>);
}
void test()
{
const S s;
foo(s); // error
foo(S{});
S s2;
foo(s2); // error
}
T
将推导为
S const&
S
S&
为什么T
不推导为
S const
S
S
为什么 T
在左值情况下保留引用而不在右值情况下?
转发引用的一个怪癖是你永远不会“只有一个值”。
当T
推导为S
时,这只是因为函数实际上接受S&&
。
当您传递局部变量时,类型推导会识别出这些是左值,因此它将它们绑定到常规引用。在 const S s
的情况下 const
一个。函数签名“改变”以反映这一点。
您将拥有 (const S&)&&
,标准指示折叠为仅 const S&
,然后您将拥有 (S&)&&
,其折叠为仅 S&
,每个引用折叠的规则。
See for yourself(现场演示)
就是这样 forwarding reference works in template argument deduction:
(强调我的)
4) If P is an rvalue reference to a cv-unqualified template parameter (so-called forwarding reference), and the corresponding function call argument is an lvalue, the type lvalue reference to A is used in place of A for deduction (Note: this is the basis for the action of
std::forward
这意味着,如果传递了一个左值,T
将被推导为左值引用。否则,如果T
在转发引用中被推导为左值和右值的相同类型,则无法使用std::forward
再次执行完美转发;即当传递左值时作为左值转发,当传递右值时作为右值转发。