Есть ли реальный вариант использования квалификаторов ссылок на функции?

Недавно я узнал о function's reference qualifiers, например.

struct foo
{
    void bar() {}
    void bar1() & {}
    void bar2() && {}
};

Где мне может понадобиться эта функция, есть ли реальный вариант использования этой языковой функции?


person tommyk    schedule 19.01.2015    source источник
comment
Связано: stackoverflow.com/questions/8610571/   -  person Caramiriel    schedule 19.01.2015
comment
Самый полезный известный мне способ — использовать для оператора преобразования перегрузку struct foo { operator std::string () const & { return s; } operator std::string () && { return std::move(s); } std::string s; };. Поэтому foo func() { return {"string"s}; } ... std::string s = foo(); не подразумевает ненужного копирования и уничтожения непустого std::string объекта.   -  person Tomilov Anatoliy    schedule 20.01.2015
comment
@Orient, пожалуйста, добавьте это как ответ, так как это действительно интересно и может быть кому-то полезно.   -  person tommyk    schedule 21.01.2015


Ответы (2)


В основном есть два варианта использования:

  1. Чтобы обеспечить оптимизированную перегрузку, например, чтобы переместить элемент из временного объекта вместо его копирования.
  2. Предотвращение неправильного использования API. Например, никто не ожидал

    int a = 1 += 2;
    

    работать, и это также вызовет ошибку компиляции. Однако

    string b = string("foo") += "bar";
    

    является допустимым, если operator += объявлен как

    string & operator += (string const & o);
    

    как это обычно бывает. Также это имеет неприятный побочный эффект предоставления ссылки lvalue на ваше значение rvalue. Плохая идея. Этого можно легко избежать, объявив оператор как

    string & operator += (string const & o) &;
    
person Joe    schedule 19.01.2015

Где мне может понадобиться эта функция, есть ли реальный вариант использования этой языковой функции?

Показанный вами пример довольно бесполезен, он более полезен, когда у вас есть перегруженная функция, одна версия которой работает с lvalue, а другая — с rvalue.

Рассмотрим тип, немного похожий на std::stringstream, который владеет строкой и возвращает ее по значению. Если объект является значением r, он может перемещать строку вместо ее копирования.

class StringBuilder
{
public:
  std::string get() const& { return m_str; }
  std::string get() && { return std::move(m_str); }

private:
  std::string m_str;
};

Это означает, что когда вы возвращаете StringBuilder из функции и хотите получить из нее строку, вам не нужна копия:

std::string s = buildString().get();

В более общем смысле, если для функции f(const X&) было бы полезно перегрузить ее с помощью f(X&&), то с учетом функции-члена X::f() может быть полезным изменить ее на X::f() const& и перегрузить с помощью X::f()&&

person Jonathan Wakely    schedule 19.01.2015