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

Which is better and more recommended? Or is there an alternative which is better than both?

Niall
  • 30,036
  • 10
  • 99
  • 142
Nan Hua
  • 3,414
  • 3
  • 17
  • 24
  • I added a final sentence to the question, allowing for the possibility (as in this case) to recommend *neither* approach. "Or is there an alternative which is better than both?" – Aaron McDaid Aug 03 '15 at 19:40
  • 2
    Highly relevant: [how to pass parameters](http://stackoverflow.com/q/15600499/2069064) and [advantages of forward](http://stackoverflow.com/q/3582001/2069064). – Barry Aug 03 '15 at 19:42
  • Pre C++11, you can't even use the first one, so you have must use the latter then! – Aaron McDaid Aug 03 '15 at 19:50
  • 2
    @AaronMcDaid: You can't use either of them pre-C++11. – Benjamin Lindley Aug 03 '15 at 20:07
  • @BenjaminLindley. Doh. I had forgetten about the varags! It's amazing how one takes some things for granted after a few years :-) – Aaron McDaid Aug 03 '15 at 20:20

3 Answers3

2

The first one, but you need to forward your arguments during expansion by using std::forward<T>. This allows your parameter pack to be expanded while properly deducing your arguments.

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

As an example, say you have a function declared as follows:

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

Attempting to use said function with a temporary value or rvalue will fail:

some_func( 5 );

This is due to the fact that 5 is a constant, which cannot be assigned to int&.

bku_drytt
  • 3,169
  • 17
  • 19
  • Just a suggestion, I would make clear that neither are recommended. In particular, the first one is really bad because it gives the impression that it's forwarding, due to the `&&` in the params, when it's actually not. – Aaron McDaid Aug 03 '15 at 19:38
  • Yes, I specified that std::forward should be used. – bku_drytt Aug 03 '15 at 19:40
2

The Args && will accept lvalues, and rvalues by reference and enables them to be forwarded on maintaining their original value category. I would favour that version (and use std::forward).

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

Note the idiomatic use of std::forward, it does not include the && of the Args&&.

There are a number of articles on the mechanics and use of std::forward and reference collapsing, here and the Scott Meyers classic on "forwarding (or universal) references".

Community
  • 1
  • 1
Niall
  • 30,036
  • 10
  • 99
  • 142
1

Let's say you call your function with the following arguments:

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

In the first case, it's equivalent to calling this function:

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

In the second case it's equivalent to calling this function:

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

The second is recommended if you want to forward argument while avoiding copies (but use std::forward then!)

Caninonos
  • 1,214
  • 7
  • 12