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...);
}
哪个更好,更推荐?或者是否有比两者更好的替代方案?
答案 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&&
和参考折叠,here和Scott 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) { /* ... */ }
然后!)