我对此计划有一些疑问:
#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
template <typename T> void foo ( T x )
{
auto r=ref(x);
cout<<boolalpha;
cout<<is_same<T&,decltype(r)>::value;
}
int main()
{
int x=5;
foo (x);
return 0;
}
输出结果为:
false
我想知道,如果std::ref
没有返回对象的引用,那么它会做什么?基本上,有什么区别:
T x;
auto r = ref(x);
和
T x;
T &y = x;
另外,我想知道为什么存在这种差异?当我们有引用时(std::ref
),为什么我们需要std::reference_wrapper
或T&
?
答案 0 :(得分:58)
好ref
构造一个适当的reference_wrapper
类型的对象来保存对象的引用。这意味着当您申请时:
auto r = ref(x);
这会返回reference_wrapper
,而不是x
的直接引用(即T&
)。此reference_wrapper
(即r
)代替T&
。
当你想模仿一个可以复制的对象的reference_wrapper
时,reference
非常有用(它是 copy-constructible 和 copy-分配)。
在C ++中,一旦您为对象创建引用(比如说y
)(比如说x
),那么y
和x
会共享相同的基础解决。此外,y
不能引用任何其他对象。此外,您无法创建引用数组,即这样的代码将引发错误:
#include <iostream>
using namespace std;
int main()
{
int x=5, y=7, z=8;
int& arr[] {x,y,z}; // error: declaration of 'arr' as array of references
return 0;
}
但这是合法的:
#include <iostream>
#include <functional> // for reference_wrapper
using namespace std;
int main()
{
int x=5, y=7, z=8;
reference_wrapper<int> arr[] {x,y,z};
for (auto a: arr)
cout << a << " ";
return 0;
}
/* OUTPUT:
5 7 8
*/
使用cout << is_same<T&,decltype(r)>::value;
谈论您的问题,解决方案是:
cout << is_same<T&,decltype(r.get())>::value; // will yield true
让我告诉你一个程序:
#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
int main()
{
cout << boolalpha;
int x=5, y=7;
reference_wrapper<int> r=x; // or auto r = ref(x);
cout << is_same<int&, decltype(r.get())>::value << "\n";
cout << (&x==&r.get()) << "\n";
r=y;
cout << (&y==&r.get()) << "\n";
r.get()=70;
cout << y;
return 0;
}
/* Ouput:
true
true
true
70
*/
看到这里我们了解三件事:
reference_wrapper
对象(此处为r
)可用于创建引用数组,这是T&
无法实现的。
r
实际上就像一个真正的参考(请参阅r.get()=70
如何更改y
的值)。
r
与T&
不同,但r.get()
不同。这意味着r
拥有T&
,即顾名思义是围绕参考 T&
的包装。
我希望这个答案足以解释你的疑虑。
答案 1 :(得分:39)
std::reference_wrapper
,以便能够在按值传递的上下文中通过引用传递对象。
例如,std::bind
可以将std::ref()
接收到某个内容,按值传输,然后将其解压缩回参考中。
void print(int i) {
std::cout << i << '\n';
}
int main() {
int i = 10;
auto f1 = std::bind(print, i);
auto f2 = std::bind(print, std::ref(i));
i = 20;
f1();
f2();
}
此代码段输出:
10
20
i
的值已在初始化时存储(按值)到f1
,但f2
按值保存std::reference_wrapper
,并且因此表现得像int&
。
答案 2 :(得分:23)
引用(T&
或T&&
)是C ++语言中的特殊元素。它允许通过引用操作对象,并且在该语言中具有特殊用例。例如,您无法创建标准容器来保存引用:vector<T&>
生成错误并生成编译错误。
另一方面,std::reference_wrapper
是能够保存引用的C ++对象。因此,您可以在标准容器中使用它。
std::ref
是一个标准函数,在其参数上返回std::reference_wrapper
。同样的想法,std::cref
将std::reference_wrapper
返回给const引用。
std::reference_wrapper
的一个有趣属性是,它有一个operator T& () const noexcept;
。这意味着即使它是一个真正的对象,它也可以自动转换为它所持有的引用。所以:
operator T& () const noexcept;
,它可以在任何可以使用引用的地方使用,因为它会自动转换为它。