1
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...);
  }

哪个更好,更推荐?或者有没有比两者都更好的选择?

4

3 回答 3

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& ) {}

尝试将所述函数与临时值或右值一起使用将失败:

some_func( 5 );

这是因为 5 是一个常数,不能赋值给int&

于 2015-08-03T19:37:17.987 回答
2

Args &&通过引用接受左值和右值,并使它们能够在保持其原始值类别的情况下被转发。我会赞成那个版本(并使用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和引用折叠的文章,这里Scott Meyers关于“转发(或通用)引用”的经典。

于 2015-08-03T19:37:38.050 回答
1

假设您使用以下参数调用函数:

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::forwardthen!)

于 2015-08-03T19:38:06.187 回答