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_wrappertypes的对象来保存一个对象的引用。 这意味着当你申请: –
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;它可以在任何可以使用引用的地方使用,因为它会自动转换为它。