Должны ли все / большинство функций setter в C++11 быть записаны как шаблоны функций, принимающие универсальные ссылки?
рассмотрим класс X
С N
переменные-члены, каждый из некоторых копировать и движимое тип, и N
соответствующий сеттера.
В C++98 определение X
скорее всего, будет выглядеть примерно так:
class X
{
public:
void set_a(A const& a) { _a = a; }
void set_b(B const& b) { _b = b; }
...
private:
A _a;
B _b;
...
};
функции сеттера класса X
выше можно привязать как к аргументам lvalue, так и к аргументам rvalue. В зависимости от фактического аргумента, это может результат в создании временных и будет в конечном итоге привести к назначению копии; из-за этого, не поддается копированию типы не поддерживаются этой конструкции.
С C++11 мы имеем семантику перемещения, совершенную пересылку и универсальные ссылки (терминология Скотта Мейерса), которые позволяют более эффективно и обобщенно использовать функции сеттера, переписывая их следующим образом:
class X
{
public:
template<typename T>
void set_a(T&& a) { _a = std::forward<T>(a); }
template<typename T>
void set_b(T&& b) { _b = std::forward<T>(b); }
...
private:
A _a;
B _b;
...
};
универсальные ссылки могут привязываться к const
/неconst
,volatile
/неvolatile
, и в любой конвертируемый тип в целом, избегая создания временных значений и передачи значений прямо в operator =
. не поддается копированию,движимое типы поддерживаются. Возможно, нежелательные Привязки могут быть устранены либо посредством static_assert
или std::enable_if
.
так что мой вопрос: как руководство по проектированию, должны ли все (скажем, большинство) функции setter в C++11 быть записаны как шаблоны функций, принимающие универсальный рекомендации?
помимо более громоздкого синтаксиса и невозможности использования Intellisense-подобных вспомогательных инструментов при написании кода в этих функциях setter, существуют ли какие-либо соответствующие недостатки с гипотетическим принципом "напишите функции сеттера как шаблоны функций, принимающие универсальные ссылки, когда это возможно"?
1 ответ:
вы знаете классы A и B, поэтому вы знаете, являются ли они подвижными или нет, и если эта конструкция в конечном итоге необходима. Для чего-то вроде
std::string
, это пустая трата времени на изменение существующего кода, если вы не знаете, что у вас есть проблемы с производительностью здесь. Если вы имеете дело сauto_ptr
, то пришло время, чтобы вырвать его и использоватьunique_ptr
.Это, как правило, предпочитали теперь принимает доводы по стоимости если вы не знаете ничего более конкретного-такой как
void set_a(A a) { _a = std::move(a); }
Это позволяет использовать любой из конструкторов
A
не требуя ничего, кроме подвижности и предлагает относительно интуитивно понятный интерфейс.