В чем разница между этими двумя определениями шаблонов функций?

template <typename Func, typename... Args>
static void WraperFunc(Func func, Args &&... args) {
SomeFunc(func, args...);
}

против

template <typename Func, typename... Args>
static void WraperFunc(Func func, Args ... args) {
SomeFunc(func, args...);
}

Что лучше и больше рекомендуется? Или есть альтернатива, которая лучше, чем оба?

1

Решение

Args && будет принимать lvalues ​​и rvalues ​​по ссылке и позволяет их пересылать при сохранении их оригинала категория стоимости. Я бы предпочел эту версию (и использовать std::forward).

template <typename Func, typename... Args>
static void WraperFunc(Func func, Args &&... args) {
SomeFunc(func, std::forward<Args>(args)...);
//             ^^^^^^^^^^^^ Use of forward
}

Обратите внимание на идиоматическое использование std::forward, это не включает && из Args&&,

Есть целый ряд статей по механике и использованию std::forward и ссылка рушится, Вот и Скотт Мейерс классик на «пересылка (или универсальные) ссылки».

2

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

Первый, но вы должны пересылать свои аргументы во время расширения, используя std::forward<T>, Это позволяет расширить ваш пакет параметров при правильном выводе ваших аргументов.

template <typename Func, typename... Args>
static void WraperFunc(Func func, Args &&... args)
{
// note that we use std::forward<Args>( args )... to perfect forward our arguments
SomeFunc(func, std::forward<Args>( args )...);
}

Например, скажем, у вас есть функция, объявленная следующим образом:

template <typename T>
void some_func( T& ) {}

Попытка использовать указанную функцию с временным значением или значением r не удастся:

some_func( 5 );

Это связано с тем, что 5 является константой, которую нельзя присвоить int&,

2

Допустим, вы вызываете свою функцию со следующими аргументами:

void (*foo)(int, char, float) = /* ... */;
const int i = 0;
char j;
WraperFunc(foo, i, j, 0.42);

В первом случае это эквивалентно вызову этой функции:

void WraperFunc(void (*foo)(int, char, float), int i, char c, float j) { /* ... */ }

Во втором случае это эквивалентно вызову этой функции:

void WraperFunc(void (*foo)(int, char, float), const int& i, char& c, float&& j) { /* ... */ }

Второй рекомендуется, если вы хотите пересылать аргументы, избегая копий (но используйте std::forward затем!)

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