C++ std::ref(T) 和 T& 之间的区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33240993/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++ Difference between std::ref(T) and T&?
提问by CppNITR
I have some questions regarding this program:
我有一些关于这个程序的问题:
#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;
}
The output is:
输出是:
false
I want to know, if std::ref
doesn't return the reference of an object, then what does it do? Basically, what is the difference between:
我想知道,如果std::ref
不返回对象的引用,那么它有什么作用?基本上,有什么区别:
T x;
auto r = ref(x);
and
和
T x;
T &y = x;
Also, I want to know why does this difference exist? Why do we need std::ref
or std::reference_wrapper
when we have references (i.e. T&
)?
另外,我想知道为什么会存在这种差异?为什么我们需要std::ref
或std::reference_wrapper
当我们有参考资料(即T&
)?
采纳答案by Ankit Acharya
Well ref
constructs an object of the appropriate reference_wrapper
type to hold a reference to an object. Which means when you apply:
Wellref
构造一个适当reference_wrapper
类型的对象来保存对对象的引用。这意味着当您申请时:
auto r = ref(x);
This returns a reference_wrapper
and not a direct reference to x
(ie T&
). This reference_wrapper
(ie r
) instead holds T&
.
这将返回 areference_wrapper
而不是对x
(ie T&
)的直接引用。这reference_wrapper
(即r
)反而成立T&
。
A reference_wrapper
is very useful when you want to emulate a reference
of an object which can be copied (it is both copy-constructibleand copy-assignable).
一reference_wrapper
,当你想模仿是非常有用的reference
,可复制的对象(它既是拷贝构造和拷贝分配)。
In C++, once you create a reference (say y
) to an object (say x
), then y
and x
share the same base address. Furthermore, y
cannot refer to any other object. Also you cannot create an array of referencesie code like this will throw an error:
在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;
}
However this is legal:
但是这是合法的:
#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
*/
Talking about your problem with cout << is_same<T&,decltype(r)>::value;
, the solution is:
谈论您的问题cout << is_same<T&,decltype(r)>::value;
,解决方案是:
cout << is_same<T&,decltype(r.get())>::value; // will yield true
Let me show you a program:
我给你看一个程序:
#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
*/
See here we get to know three things:
看到这里我们就知道三件事:
A
reference_wrapper
object (herer
) can be used to create an array of referenceswhich was not possible withT&
.r
actually acts like a real reference (see howr.get()=70
changed the value ofy
).r
is not same asT&
butr.get()
is. This means thatr
holdsT&
ie as its name suggests is a wrapper around a referenceT&
.
甲
reference_wrapper
对象(这里r
)可被用于创建引用的数组这是不可能的T&
。r
实际上就像一个真正的引用(看看r.get()=70
的值是如何改变的y
)。r
与T&
但不一样r.get()
。这意味着r
holdT&
ie 顾名思义是一个引用的包装器T&
。
I hope this answer is more than enough to explain your doubts.
我希望这个答案足以解释你的疑惑。
回答by Quentin
std::reference_wrapper
is recognized by standard facilities to be able to pass objects by reference in pass-by-value contexts.
std::reference_wrapper
被标准设施识别为能够在传值上下文中通过引用传递对象。
For example, std::bind
can take in the std::ref()
to something, transmit it by value, and unpacks it back into a reference later on.
例如,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();
}
This snippet outputs :
此代码段输出:
10
20
The value of i
has been stored (taken by value) into f1
at the point it was initialized, but f2
has kept an std::reference_wrapper
by value, and thus behaves like it took in an int&
.
的值在初始化时i
已被存储(按值获取)f1
,但f2
保留了一个std::reference_wrapper
by 值,因此它的行为就像它在一个int&
.
回答by Serge Ballesta
A reference (T&
or T&&
) is a special element in C++ language. It allows to manipulate an object by referenceand has special use cases in the language. For example, you cannot create a standard container to hold references: vector<T&>
is ill formed and generates a compilation error.
引用(T&
或T&&
)是 C++ 语言中的特殊元素。它允许通过引用操作对象,并且在语言中有特殊用例。例如,您不能创建标准容器来保存引用:格式vector<T&>
错误并生成编译错误。
A std::reference_wrapper
on the other hand is a C++ object able to hold a reference. As such, you can use it in standard containers.
std::reference_wrapper
另一方面,A是一个能够保存引用的 C++ 对象。因此,您可以在标准容器中使用它。
std::ref
is a standard function that returns a std::reference_wrapper
on its argument. In the same idea, std::cref
returns std::reference_wrapper
to a const reference.
std::ref
是一个标准函数,std::reference_wrapper
它在其参数上返回 a 。同理,std::cref
返回std::reference_wrapper
一个常量引用。
One interesting property of a std::reference_wrapper
, is that it has an operator T& () const noexcept;
. That means that even if it is a true object, it can be automatically converted to the reference that it is holding. So:
a 的一个有趣属性std::reference_wrapper
是它有一个operator T& () const noexcept;
。这意味着即使它是一个真正的 object,它也可以自动转换为它所持有的引用。所以:
- as it is a copy assignable object, it can be used in containers or in other cases where references are not allowed
- thanks to its
operator T& () const noexcept;
, it can be used anywhere you could use a reference, because it will be automatically converted to it.
- 因为它是一个可复制赋值的对象,所以它可以用于容器或其他不允许引用的情况
- 由于它的
operator T& () const noexcept;
,它可以在任何可以使用引用的地方使用,因为它会自动转换为它。