web-dev-qa-db-ja.com

std :: reference_wrapperを正しく使用する方法

std::reference_wrapperを理解しようとしています。

次のコードは、参照ラッパーが参照とまったく同じように動作しないことを示しています。

#include <iostream>
#include <vector>
#include <functional>

int main()
{
    std::vector<int> numbers = {1, 3, 0, -8, 5, 3, 1};

    auto referenceWrapper = std::ref(numbers);
    std::vector<int>& reference = numbers;

    std::cout << reference[3]              << std::endl;
    std::cout << referenceWrapper.get()[3] << std::endl; 
              // I need to use get ^
              // otherwise does not compile.
    return 0;
}

私がそれを正しく理解していれば、暗黙的な変換はメンバー関数の呼び出しには適用されません。これは固有の制限ですか? std::reference_wrapper::getを頻繁に使用する必要がありますか?

別のケースはこれです:

#include <iostream>
#include <functional>

int main()
{
    int a = 3;
    int b = 4;
    auto refa = std::ref(a);
    auto refb = std::ref(b);
    if (refa < refb)
        std::cout << "success" << std::endl;

    return 0;
}

これは正常に機能しますが、main定義の上にこれを追加すると:

template <typename T>
bool operator < (T left, T right)
{
    return left.someMember();
}

コンパイラはテンプレートをインスタンス化しようとし、暗黙的な変換と組み込み演算子を忘れます。

この動作は固有のものですか、それともstd::reference_wrapperについて重要な何かを誤解していますか?

35
Martin Drozdik

クラス_std::reference_wrapper<T>_は、暗黙の変換演算子を_T&_に実装します。

_operator T& () const noexcept;
_

より明確なゲッター:

_T& get() const noexcept;
_

暗黙の演算子は、T(または_T&_)が必要なときに呼び出されます。例えば

_void f(some_type x);
// ...
std::reference_wrapper<some_type> x;
some_type y = x; // the implicit operator is called
f(x);            // the implicit operator is called and the result goes to f.
_

ただし、Tが必ずしも必要ではない場合があり、この場合はgetを使用する必要があります。これは、ほとんどの場合、自動型推論コンテキストで発生します。例えば、

_template <typename U>
g(U x);
// ...
std::reference_wrapper<some_type> x;
auto y = x; // the type of y is std::reference_wrapper<some_type>
g(x);       // U = std::reference_wrapper<some_type>
_

上記の_some_type_の代わりに_std::reference_wrapper<some_type>_を取得するには

_auto y = x.get(); // the type of y is some_type
g(x.get());       // U = some_type
_

または、上記の最後の行をg<some_type>(x);で置き換えることもできます。ただし、テンプレート化された演算子(たとえば、ostream::operator <<())の場合、型を明示的に指定できないと思います。

39
Cassio Neri