Устаревает ли оператор C++ 11 && (ссылка на R-значение) шаблон проектирования «прокси-объект»?

Статья 30 Скотта Мейерса "более эффективный C++" отображает шаблон программирования «прокси-объект».

Проблема в том, если у вас:

X x;
x[3]=42; 
cout<<x[3]

... вам нужна перегрузка оператора [] X, чтобы иметь возможность различать использование L-значения и R-значения.

(возможно, вам нужен другой код для запуска, например, в первом случае может потребоваться интенсивное копирование, но во втором случае, возможно, мы можем просто передать ссылку).

Шаблон прокси состоит в том, что X содержит класс Proxy, а перегруженные версии operator[] X возвращают объект типа Proxy.

Итак, этот код становится:

X x;
{some Proxy object}=42; 
cout<<{some Proxy object}

Теперь нам просто нужно дать нашему прокси-объекту переопределение для «operator=», которое обрабатывает первый случай, и переопределение для «преобразования в std::string или char*», которое обрабатывает второй.

И попытка C++ найти подходящее преобразование типов приведет к соответствующему переопределению.

Однако эта книга была написана до C++11, а одной из основных особенностей C++11 является новый оператор && (ссылка на R-значение).

Существует ли теперь более простой способ кодирования отдельных назначений R-значения и L-значения?

Является ли этот шаблон проектирования прокси-объекта устаревшим?


person P i    schedule 23.10.2014    source источник


Ответы (1)


Нет, я не верю, что здесь есть альтернативный механизм.

Хотя методы с указанием ссылки могут обеспечивать различное поведение в определенных сценариях, перегрузки разрешаются в зависимости от состояния объекта, для которого они были вызваны. Они не разрешены при использовании объекта, который они возвращают.

В следующем живом примере я создаю оболочку вокруг std::vector, пытаясь автоматически увеличить вектор при назначении в индекс и разрешить неопределенное поведение при простом чтении из индекса.

Но это так не работает:

template <typename T>
struct AutoVector
{
    std::vector<T> m_vec;
    AutoVector() { m_vec.resize(1); }

    T& operator[](const size_t index) &
    {
        std::cout << "Inside operator[" << index << "]&\n";
        if (m_vec.size() < index)
            m_vec.resize(index);
        return m_vec[index];
    }

    T operator[](const size_t index) &&
    {
        std::cout << "Inside operator[" << index << "]&&\n";
        return m_vec[index];
    }
};

Если это вызывается следующими способами, оба будут вызывать operator[] & с указанием lvalue:

AutoVector<int> avec;
avec[4] = 6;
std::cout << avec[4] << "\n";
    --> Inside operator[4]&
    --> Inside operator[4]&
    --> 6

Если это вызывается для временного объекта, он может вызывать operator[] && с указанием rvalue:

std::cout << AutoVector<int>()[0] << "\n";
    --> Inside operator[0]&&
    --> 0

Это не имеет желаемого поведения. Применение такого же теста к прокси-объекту, возвращаемому operator[], обычно приводит к вызову методов с указанием rvalue во всех случаях, если только прокси не был захвачен и назван. Это все равно не отражало бы, как использовался прокси.

person Michael Urman    schedule 23.10.2014