C ++ std :: ref(T)与T&的区别
我有关于这个程序的一些问题:
#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;
另外,我想知道为什么这种差异存在? 当我们有引用(即T&
)时,为什么我们需要std::ref
或std::reference_wrapper
?
那么ref
构造一个适当的reference_wrapper
types的对象来保存一个对象的引用。 这意味着当你申请: –
auto r = ref(x);
这返回一个reference_wrapper
&而不是直接引用x (ie T&)
。 这个reference_wrapper (ie r)
代替T&
。
当你想模拟一个可以被复制的对象的reference
(它既是可复制的,也可以是可复制的)时, reference_wrapper
是非常有用的。
在C ++中,一旦你创build了一个object (say x)
reference (say y)
的reference (say y)
object (say x)
,那么y
和x
共享相同的base address
。 此外, y
不能引用任何其他对象。 你也不能创build一个array of references
即像这样的代码会抛出一个错误:
#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)>::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
)可以用来创buildT&
不可能array of references
。 -
r
实际上就像一个真实的reference
(看看r.get()=70
如何改变y
的值)。 -
r
与T&
不相同,但r.get()
是。 这意味着r
持有T&
ie,因为它的名称暗示了wrapper around reference T&
。
我希望这个答案足以解释你的疑惑。
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
的值,因此performance就像它在一个int&
。
引用( T&
T&&
)是C ++语言中的一个特殊元素。 它允许通过引用来操作对象,并在该语言中有特殊用例。 例如,你不能创build一个标准的容器来保存引用: 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;
它可以在任何可以使用引用的地方使用,因为它会自动转换为它。