このプログラムに関していくつか質問があります。
#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);
_
これは、x
(つまり_reference_wrapper
_)への直接参照ではなく、_T&
_を返します。この_reference_wrapper
_(つまりr
)は、代わりに_T&
_を保持します。
_reference_wrapper
_は、コピー可能なオブジェクトのreference
をエミュレートするときに非常に便利です(両方ともcopy-constructibleとcopy-assignable)。
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つのことを理解してください。
_reference_wrapper
_オブジェクト(ここではr
)を使用して、参照の配列を作成できますが、これは_T&
_では不可能でした。
r
は実際には実際の参照のように動作します(r.get()=70
がy
の値を変更した方法を参照してください)。
r
は_T&
_と同じではありませんが、r.get()
は同じです。これは、r
が_T&
_を保持することを意味します。つまり、その名前が示すように、参照を囲むラッパー _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
_を保持しているため、動作します_int&
_を取り込んだように。
参照(_T&
_または_T&&
_)は、C++言語の特別な要素です。参照によってオブジェクトを操作することができ、言語に特別なユースケースがあります。たとえば、参照を保持する標準コンテナを作成することはできません。_vector<T&>
_は不正な形式であり、コンパイルエラーを生成します。
一方、_std::reference_wrapper
_は、参照を保持できるC++オブジェクトです。そのため、標準のコンテナで使用できます。
_std::ref
_は、引数で_std::reference_wrapper
_を返す標準関数です。同じアイデアで、_std::cref
_はconst参照に_std::reference_wrapper
_を返します。
_std::reference_wrapper
_の興味深い特性の1つは、operator T& () const noexcept;
があることです。つまり、真のオブジェクトであってもであっても、保持している参照に自動的に変換できます。そう:
operator T& () const noexcept;
のおかげで、参照を使用できる場所であればどこでも使用できます。これは、参照に自動的に変換されるためです。