1

Say I have a function foo() with takes advantage of c++ variadic templates feature. Now, what's the difference between these implementations:

template <typename... Args>
void foo(Args... args) {
whatever(args...);
}

template<typename... Args>
void foo(Args&... args) {
whatever(args...);
}

template<typename... Args>
void foo(Args... args) {
whatever(&args...);
}

template<typename... Args>
void foo(Args&&... args) {
whatever(std::forward<Args>(args)...);
}
ibe
  • 185
  • 1
  • 11

2 Answers2

2

The first one takes its arguments by value. The second one takes its arguments by lvalue reference (so non-const rvalues cannot be used). The third one also takes its arguments by value, but passes pointers to whatever. The fourth one takes its arguments by forwarding reference and perfect-forwards them to whatever.

There is nothing magical about the variadic templates; the rules are the same as if there were only one argument.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
2
template <typename... Args>
void foo(Args... args) {
    whatever(args...);
}

foo gets copies of args and passes them to whatever as l-values.

template<typename... Args> 
void foo(Args&... args) {
     whatever(args...);
}

foo gets l-value references to args and passes them to whatever as l-values.

template<typename... Args>
void foo(Args... args) {
    whatever(&args...);
}

foo gets copies of args and passes them to whatever as pointers to l-values. Be careful of object lifetimes here.

template<typename... Args>
void foo(Args&&... args) {
    whatever(std::forward<Args>(args)...);
}

foo gets forwarding references to args. Whether they are l-values or r-values depends on what happens at the call site. They are then perfect-forwarded to whatever, preserving their reference type. Scott Meyers originally called these "universal" references, but forwarding reference is the preferred terminology now.

Tim
  • 1,517
  • 1
  • 9
  • 15