这两个函数模板定义之间的区别是什么?

时间:2015-08-03 19:31:39

标签: c++ templates c++11 rvalue-reference pass-by-rvalue-reference

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

VS

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

哪个更好,更推荐?或者是否有比两者更好的替代方案?

3 个答案:

答案 0 :(得分: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&

答案 1 :(得分:2)

Args &&将通过引用接受左值和右值,并允许它们在维持原始value category时转发。我赞成该版本(并使用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的惯用法,但不包括&&的{​​{1}}。

有很多关于Args&&和参考折叠,hereScott Meyers classic on&#34;转发(或通用)参考文献&#34;的机制和使用的文章。

答案 2 :(得分:1)

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

Sub updateTable ()

Sheets("table").Select
ActiveSheet.ListObjects("tableQueries").Range.Select
Selection.ListObject.QueryTable.Refresh BackgroundQuery:=True

 With ActiveSheet.ListObjects("tableQueries")
    .HeaderRowRange(1) = "Column 1"
    .HeaderRowRange(2) = "Column 2"
    .HeaderRowRange(3) = "Column 3"
    .HeaderRowRange(4) = "Column 4"
    .HeaderRowRange(5) = "Column 5"
    .HeaderRowRange(6) = "Column 6"
End With

End Sub

在第一种情况下,它等同于调用此函数:

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) { /* ... */ } 然后!)