Если вы собираетесь либо просто переслать вызываемый объект в другое место, либо просто вызвать вызываемый объект ровно один раз, я бы сказал, что использование std::forward
- это правильная вещь в целом. Как объяснено здесь , это будет в некотором роде сохранять категорию значений вызываемой и позволять вызывать «правильную» версию потенциально перегруженного оператора вызова функции.
Проблема в исходном потоке заключалась в том, что вызываемый объект вызывался в цикле, поэтому потенциально вызывался более одного раза. Конкретный пример из другой нити был
template <typename F>
auto map(F&& f) const
{
using output_element_type = decltype(f(std::declval<T>()));
auto sequence = std::make_unique<Sequence<output_element_type>>();
for (const T& element : *this)
sequence->push(f(element));
return sequence;
}
Здесь я считаю, что звонить std::forward<F>(f)(element)
вместо f(element)
, т.е.
template <typename F>
auto map(F&& f) const
{
using output_element_type = decltype(std::forward<F>(f)(std::declval<T>()));
auto sequence = std::make_unique<Sequence<output_element_type>>();
for (const T& element : *this)
sequence->push(std::forward<F>(f)(element));
return sequence;
}
будет потенциально проблематично. Насколько я понимаю, определяющей характеристикой r-значения является то, что на него нельзя явно ссылаться. В частности, естественно, нет возможности использовать одно и то же значение в выражении более одного раза (по крайней мере, я не могу придумать одно). Кроме того, насколько я понимаю, если вы используете std::move
или std::forward
или любой другой способ получения значения xval, даже для того же исходного объекта, результатом будет новое значение xvalue каждый раз. Таким образом, также не может быть способа ссылаться на одно и то же значение x более одного раза. Поскольку одно и то же значение r не может использоваться более одного раза, я бы сказал (см. Также комментарии под этим ответом ), что для перегруженного оператора вызова функции обычно допустимо делать то, что может быть сделано только один раз, если вызов происходит по r-значению, например:
class MyFancyCallable
{
public:
void operator () & { /* do some stuff */ }
void operator () && { /* do some stuff in a special way that can only be done once */ }
};
Реализация MyFancyCallable
может предполагать, что вызов, который выберет версию, квалифицированную &&
, не может произойти более одного раза (для данного объекта). Таким образом, я бы посчитал переадресацию одного и того же вызываемого в более чем один вызов семантически разорванным.
Конечно, технически не существует универсального определения того, что на самом деле означает продвигать или перемещать объект. В конце концов, это действительно зависит от реализации определенных типов, чтобы назначить значение там. Таким образом, вы можете просто указать в качестве части вашего интерфейса, что потенциальные вызовы, передаваемые в ваш алгоритм, должны иметь возможность иметь дело с многократным вызовом по rvalue, который ссылается на один и тот же объект. Однако это в значительной степени идет вразрез со всеми соглашениями о том, как механизм ссылок на rvalue обычно используется в C ++, и я не очень понимаю, что можно было бы получить от этого & hellip;