2016-02-11 2 views
4

Интересно, как правильно использовать идеальный перенаправленный функтор? Вот два фрагмента кода. Какой из них лучший, а если нет, то какая лучшая форма?Идеальная пересылка функтора

template<typename T, typename... Args> 
void callMe(T&& func, Args&&... args) { 
    func(std::forward<Args>(args)...); 
} 

Или

template<typename T, typename... Args> 
void callMe(T&& func, Args&&... args) { 
    std::forward<T>(func)(std::forward<Args>(args)...); 
} 

EDIT:

Повлияет ли это разрешение перегрузки? Если funcoperator() имеет ref-квалификатор для && или const &, должен ли я использовать последнюю версию и должен ли я беспокоиться о том, какую перегрузку я звоню?

Спасибо!

+0

Последнее верно, если оператор вызова функции может иметь ref-квалификатор –

+0

@PiotrSkotnicki, можете ли вы привести пример того, что вы имеете в виду? –

+1

@JohanLundberg http://coliru.stacked-crooked.com/a/2114bc29d189fde9 –

ответ

4

С исх квалифицированных operator() существует, первая версия может делать неправильные вещи. Рассмотрим:

struct C { 
    void operator()() && { std::cout << "rval\n"; } 
    void operator()() const & { std::cout << "lval\n"; } 
}; 

callMe(C{}); 

Я даю вам RValue - и ожидали бы увидеть "rval" - но в первой версии, вы всегда обрабатывать объект функции, как Lvalue - так что я действительно вижу "lval".

Таким образом, правильным решением будет второе - forward s func.


На практике я не знаю, как часто выполняются рефлексированные функции-члены, поэтому первая, вероятно, прекрасна.

+1

Прохладный. Я понятия не имел, что существует реф-квалификация. –

+0

Страх, который у меня был, - это оптимизация лямбда, где rvalue lambdas начинает неявно перемещаться из своего сохраненного внутреннего состояния, как локальные переменные. Это может дать вам некоторые хорошие повышения производительности в некоторых случаях, возможно, и отсутствие вперед будет потеряно. Но, вероятно, нет. – Yakk

+0

@Yakk Я читал, что как «возможно, невозможно правильно написать общий код на C++» – Barry

6

Идеальная пересылка полезна в том случае, если вы отправляетесь в доставляете объект (возможно, rvalue) на какую-либо другую функцию, и вы не уверены, что это значение rvalue или lvalue. В этом случае вы только используетеfunc, так что нет никакой выгоды или вреда при его пересылке.

Помните, std::forward является условным std::move, который является только отлитой для ссылки на r-значение.

Кроме того, это действительно полезно, если есть вероятность, что конструктор копирования или перемещения может быть вызван для вещи, которую вы пересылаете. Во многих случаях const T& будет прекрасно.

редактировать:

Как ягодный указывает, что делает дело, если func имеет исх квалификацию operator(). Я никогда не видел или не использовал рефлексивный метод (насколько я знаю, это очень редко). Больше в ответе Барри.

Было бы прочитать также: What is "rvalue reference for *this"?

struct C { 
    void operator()() && { std::cout << "rval\n"; } 
    void operator()() const & { std::cout << "lval\n"; } 
}; 

callMe(C{}); 
+0

+1 согласовано.Для других читателей я хотел бы отметить, что нет никакого вреда в переадресации, если вы собираетесь использовать его, потому что 'std :: forward' - всего лишь приведение типа к значению r-value (' && ') или l -value reference ('&'). – AndyG

+0

Не соглашайтесь на «прибыль/вред». Что, если 'T' имеет ref-qual' operator()'? – Barry

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