1. ホーム
  2. c++

[解決済み] C++ std::ref(T)とT&の違い?

2022-12-28 05:49:50

質問

このプログラムについて、いくつか質問があります。

#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& )?

どのように解決するのですか?

さて ref は、適切な reference_wrapper 型のオブジェクトを構築し、オブジェクトへの参照を保持します。つまり、適用すると

auto r = ref(x);

これは reference_wrapper への直接の参照ではなく x (つまり T& ). これは reference_wrapper (すなわち r を保持する代わりに T& .

A reference_wrapper をエミュレートしたい場合に非常に便利です。 reference をエミュレートしたい場合に非常に便利です。 コピーコンストラクタブル コピーアサイン可能 ).

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
*/

ここで、3つのことを知ることができます。

  1. A reference_wrapper オブジェクト(ここでは r ) を使用することで 参照の配列 では不可能だった T& .

  2. r は、実際には本当の参照のように振る舞います。 r.get()=70 の値を変更した y ).

  3. r とは異なります。 T& とは異なりますが r.get() は これはつまり r が持つ T& は、その名前が示すように を包むラッパーです。 T& .

この回答が、あなたの疑問を説明するのに十分すぎるほどであることを願っています。