std::forward 的工作和参考折叠
Working of std::forward and reference collapsing
我正在尝试熟悉完美转发的概念。
我已阅读 this and this post here. I believe I am also comfortable with the reference collapsing concept. While reading this post。我提出了以下问题
假设我们有下面的例子
Example-1
template <class T>
void foo(T &&t)
{
bar(std::forward<T>(t));
}
然后我们像这样传递它
int i= 12;
foo(i);
现在我明白了 i
会被当作 int&
我不明白
就是为什么上面回答的问题 link 提到它会是
被视为 int& &&
将崩溃为 int&.
我认为它将被视为 int&& &
将崩溃为 int&
我理解 return 两者的类型相同,但我希望第一部分正确。
我认为是int&& &
而不是int& &&
的原因如下所述,如有错误请指正
当我传入这样的东西时
int i =12;
foo(i);
那么例1就变成这样了
void foo(int &&t)
{
bar(std::forward<int>(&t)); // t is a reference now ------>A
}
现在std::forward实现是这样的
template<typename T> // For lvalues (T is T&),
T&& std::forward(T&& param) // take/return lvalue refs.
{ // For rvalues (T is T),
return static_cast<T&&>(param); // take/return rvalue refs.
}
所以当我们的解决方案应用于它时。变成
return static_cast<int&&>(¶m) ; //¶m since we passed &t in A
我们得到
int&& & and not `int& &&` please correct me if I am wrong
当您将 i
作为参数传递给 foo
时:
int i = 12;
foo(i);
表达式i
有一个左值类别,因此T
被推导为int&
,所以例子1变成:
void foo<int&>(int& && t) // `int& t` due to reference collapsing
// | \ /
// +--> T = int&
{// V
bar(std::forward<int&>(t));
}
现在,在 std::forward
中,param
的类型明确指定为 int&
,因此:
int& && std::forward<int&>(typename std::remove_reference<int&>::type& param)
// ^~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
// |
{// V
return static_cast<int& &&>(param); // `int&` due to reference collapsing
}
恢复了i
的左值类别。
为了清楚起见,当参数表达式的值类别是右值时会发生这种情况:
foo(12); // -> foo<int>(12);
// |
// v~~~~~~~~~+
void foo<int>(int && t) // `int&& t`
// | \ /
// +--> T = int
{// V
bar(std::forward<int>(t));
}// |
// V
int && std::forward<int>(typename std::remove_reference<int>::type& param)
// ^~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
// |
{// V
return static_cast<int &&>(param); // `int&&`
}
并且当类型模板参数明确指定为int&&
时:
foo<int&&>(12);
// ^~~~+
// V
void foo<int&&>(int&& && t) // `int&& t` due to reference collapsing
// | \ /
// | \ /
// +----> T = int&&
{// V
bar(std::forward<int&&>(t));
}// |
// V
int&& && std::forward<int&&>(typename std::remove_reference<int&&>::type& param)
// ^~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
// |
{// V
return static_cast<int&& &&>(param); // `int&&` due to reference collapsing
}
我正在尝试熟悉完美转发的概念。
我已阅读 this and this post here. I believe I am also comfortable with the reference collapsing concept. While reading this
假设我们有下面的例子
Example-1
template <class T>
void foo(T &&t)
{
bar(std::forward<T>(t));
}
然后我们像这样传递它
int i= 12;
foo(i);
现在我明白了 i
会被当作 int&
我不明白
就是为什么上面回答的问题 link 提到它会是
被视为 int& &&
将崩溃为 int&.
我认为它将被视为 int&& &
将崩溃为 int&
我理解 return 两者的类型相同,但我希望第一部分正确。
我认为是int&& &
而不是int& &&
的原因如下所述,如有错误请指正
当我传入这样的东西时
int i =12;
foo(i);
那么例1就变成这样了
void foo(int &&t)
{
bar(std::forward<int>(&t)); // t is a reference now ------>A
}
现在std::forward实现是这样的
template<typename T> // For lvalues (T is T&),
T&& std::forward(T&& param) // take/return lvalue refs.
{ // For rvalues (T is T),
return static_cast<T&&>(param); // take/return rvalue refs.
}
所以当我们的解决方案应用于它时。变成
return static_cast<int&&>(¶m) ; //¶m since we passed &t in A
我们得到
int&& & and not `int& &&` please correct me if I am wrong
当您将 i
作为参数传递给 foo
时:
int i = 12;
foo(i);
表达式i
有一个左值类别,因此T
被推导为int&
,所以例子1变成:
void foo<int&>(int& && t) // `int& t` due to reference collapsing
// | \ /
// +--> T = int&
{// V
bar(std::forward<int&>(t));
}
现在,在 std::forward
中,param
的类型明确指定为 int&
,因此:
int& && std::forward<int&>(typename std::remove_reference<int&>::type& param)
// ^~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
// |
{// V
return static_cast<int& &&>(param); // `int&` due to reference collapsing
}
恢复了i
的左值类别。
为了清楚起见,当参数表达式的值类别是右值时会发生这种情况:
foo(12); // -> foo<int>(12);
// |
// v~~~~~~~~~+
void foo<int>(int && t) // `int&& t`
// | \ /
// +--> T = int
{// V
bar(std::forward<int>(t));
}// |
// V
int && std::forward<int>(typename std::remove_reference<int>::type& param)
// ^~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
// |
{// V
return static_cast<int &&>(param); // `int&&`
}
并且当类型模板参数明确指定为int&&
时:
foo<int&&>(12);
// ^~~~+
// V
void foo<int&&>(int&& && t) // `int&& t` due to reference collapsing
// | \ /
// | \ /
// +----> T = int&&
{// V
bar(std::forward<int&&>(t));
}// |
// V
int&& && std::forward<int&&>(typename std::remove_reference<int&&>::type& param)
// ^~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
// |
{// V
return static_cast<int&& &&>(param); // `int&&` due to reference collapsing
}