2015-02-17 3 views
2

У меня есть ряд методов следующей формыИспользование зЬй :: вперед, кроме пересылки арг другой функции

foo(std::string const & name) 
    if (name.empty()) {...} 

Я пытался следовать к сведению Скотт Мейерс на использовании универсальных ссылок и зЬй :: вперед, чтобы сделать функцию, которая эффективно принимает несколько строковых форм.

Из примера, я понимаю, как использовать std :: forward для пересылки аргумента функции другой функции, но что мне делать с выражением name.empty()?

Я думаю, что ответ std :: forward (name) .empty(), но я могу найти любую документацию, которая на самом деле говорит об этом.

ответ

3

Используйте std::forward только тогда, когда вам действительно нужно переслать категорию значений. То есть std::forward используется, чтобы гарантировать, что если ваша функция вызывается с аргументом lvalue, тогда она вызовет другую функцию с аргументом lvalue, и если ваша функция вызывается с аргументом rvalue, тогда она вызовет другую функцию с аргументом rvalue.

В случае, если вы хотите проверить, является ли строка пустой, не имеет значения, был ли аргумент значением lvalue или rvalue - функция string::empty не должна вести себя по-разному. Поэтому вам не нужен std::forward. Вместо этого достаточно всего name.empty().

+0

И использование 'std :: forward' более одного раза по одному и тому же параметру, скорее всего, является ошибкой, так как rvalues, вероятно, будут удалены при первом вводе' std :: forward'. – JohnB

2

Существует простой способ выяснить, когда использовать std::forward.

Представьте, что ваш входящий аргумент был вместо T&& t только T t - параметр значения вместо ссылки пересылки. Если вы вызовете std::move(t) во втором случае, вызов std::forward<T>(t) в первом случае - хорошая идея.

std::forward - условный ход. Он будет вызывать move, если ссылка была переданной rvalue и будет делать в основном ничего, если это не значение rvalue.

Следующий вопрос: когда вы должны указать move значение параметра?

Ну, первое общее правило: вы должны переместить параметр значения в последний раз, когда вы когда-либо ссылаетесь на него в своей области. Вы отмечаете свое состояние как «царапины» и что оно должно быть переработано в этой последней операции.

Есть еще несколько мест для использования move.

Если вы разбить его на отдельные компоненты (например, в части кортежа), и вы знаете, что доступ будет изолировано в части (std::get<N> или .member), и нет инварианты, которые будут нарушены, то move скажет код, что компонент может быть вырван из объекта. Вы можете в конечном итоге вызвать move по одной и той же переменной, но каждый раз, когда вы концептуально перемещаете только одну часть.

Это иногда отличается от вызова move на самом компоненте, так как std::get<i>(std::move(foo)) будет вести себя иначе, чем std::move(std::get<i>(foo)) когда foo содержит эталонные параметры.

Смежные вопросы