Какой вариант использования для перегрузки функций-членов в ссылочных квалификаторах?

C ++ 11 позволяет перегружать функции-члены на основе ссылочных квалификаторов:

class Foo {
public:
void f() &;   // for when *this is an lvalue
void f() &&;  // for when *this is an rvalue
};

Foo obj;
obj.f();               // calls lvalue overload
std::move(obj).f();    // calls rvalue overload

Я понимаю, как это работает, но какой вариант использования для этого?

я вижу это N2819 предложено ограничить большинство операторов присваивания в стандартной библиотеке целевыми значениями l (т.е. добавив «&«ссылки на классификаторы для операторов присваивания), но это было отклонено. Так что это был потенциальный случай использования, когда комитет решил не соглашаться с этим. Итак, опять же, что является разумным вариантом использования?

24

Решение

В классе, который предоставляет методы получения ссылок, перегрузка ref-квалификатора может активировать семантику перемещения при извлечении из значения r. Например.:

class some_class {
huge_heavy_class hhc;
public:
huge_heavy_class& get() & {
return hhc;
}
huge_heavy_class const& get() const& {
return hhc;
}
huge_heavy_class&& get() && {
return std::move(hhc);
}
};

some_class factory();
auto hhc = factory().get();

Это похоже на большие усилия, чтобы инвестировать только для того, чтобы иметь более короткий синтаксис

auto hhc = factory().get();

имеют тот же эффект, что и

auto hhc = std::move(factory().get());

РЕДАКТИРОВАТЬ: я нашел оригинал предложения, это дает три мотивирующих примера:

  1. сдерживающими operator = в lvalues ​​(ответ TemplateRex)
  2. Включение перемещения для участников (в основном это ответ)
  3. сдерживающими operator & ценностям Я полагаю, что это разумно, чтобы гарантировать, что «pointee», скорее всего, будет жив, когда «указатель» в конечном итоге разыменовывается:
struct S {
T operator &() &;
};

int main() {
S foo;
auto p1 = &foo;  // Ok
auto p2 = &S();  // Error
}

Не могу сказать, что я когда-либо лично использовал operator& перегрузки.

17

Другие решения

Одним из вариантов использования является запретить назначение временным

 // can only be used with lvalues
T& operator*=(T const& other) & { /* ... */ return *this; }

// not possible to do (a * b) = c;
T operator*(T const& lhs, T const& rhs) { return lhs *= rhs; }

в то время как не использование ссылочного квалификатора оставит вам выбор между двумя плохими

       T operator*(T const& lhs, T const& rhs); // can be used on rvalues
const T operator*(T const& lhs, T const& rhs); // inhibits move semantics

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

Ссылки @dyp в комментариях также обеспечивают расширенное обсуждение использования других (&&) перегрузка, которая может быть полезна, если вы хотите назначить на (или lvalue или rvalue) ссылки.

13

Если для f () требуется Foo temp, которая является его копией и изменена, вы можете изменить temp this вместо этого, пока вы не можете иначе

3

С одной стороны, вы можете использовать их для предотвращения семантически бессмысленных функций для вызова временных функций, таких как operator= или функции, которые изменяют внутреннее состояние и возвращают void, добавляя & в качестве эталонного классификатора.

С другой стороны, вы можете использовать его для оптимизации, например, для перемещения члена из объекта в качестве возвращаемого значения, когда у вас есть ссылка на rvalue, например, функция getName может вернуть либо std::string const& или же std::string&& в зависимости от ссылочного классификатора.

Другим вариантом использования могут быть операторы и функции, которые возвращают ссылку на исходный объект, например Foo& operator+=(Foo&) который может быть специализированным, чтобы вместо этого возвращать ссылку на rvalue, делая результат подвижным, что снова будет оптимизацией.

TL; DR: используйте это, чтобы предотвратить неправильное использование функции или для оптимизации.

0
По вопросам рекламы [email protected]