Arhn - архитектура программирования

Как правильно использовать 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?


  • std::reference_wrapper имеет несколько очень специфических применений для авторов библиотек, относящихся к идеальной пересылке и хранению аргументов (см., например, std::bind и std::thread). Я не рекомендую использовать его вне этих ситуаций. 08.08.2013
  • reference_wrapper не заменяет ссылки. 08.08.2013
  • template <typename T> bool operator < (T left, T right) { return left.someMember(); } является примером того, что НИКОГДА, НИКОГДА, НИКОГДА НЕ ДЕЛАТЬ при перегрузке оператора. Любые проблемы, возникающие из-за этого кода, не являются проблемой чего-либо еще в вашей кодовой базе. (хорошо, может быть, в каких-то смехотворно ограниченных и контролируемых namespace, которые можно найти через ADL, или в подобных других надуманных ситуациях) 08.08.2013

Ответы:


1

Класс 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 <<()) я считаю, что вы не можете явно указать тип.

08.08.2013
  • В основном это происходит в контекстах автоматического вывода типов. Основным примером такого добавления может быть использование диапазона-for или algorithm над контейнерами reference_wrapper: использование auto означает, что мы получаем wrapper, что обычно не представляет интереса, поэтому мы должны заменить его на for (ReferredType& foo) и так далее. К сожалению, слишком много для «почти всегда auto». Тем не менее, возможно, что несогласованность по-прежнему предпочтительнее хранения необработанных указателей и необходимости использовать * и -> везде в таких циклах, и, по-видимому, большинство согласится с тем, что использование reference_wrapper также передает лучшую семантику. 30.09.2018
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..