Подтвердить что ты не робот

Как правильно использовать std:: reference_wrappers

Я пытаюсь понять 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?

4b9b3361

Ответ 1

Класс std::reference_wrapper<T> реализует оператор неявного преобразования в T&:

operator T& () const noexcept;

и более явный getter:

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.

Однако иногда a 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);. Тем не менее, для templatized операторов (например, ostream::operator <<()) я считаю, что вы не можете указать тип.