Reputation: 42379
#include <type_traits>
template<typename T>
T f(T&& a, T&& b)
{
return a + b;
}
template<typename T, typename... Args>
T f(T&& a, T&& b, Args&&... args)
{
return f(a, f(b, std::forward<Args>(args)...));
}
int main()
{
f(1, 2, 3);
}
VS 2015 outputs: error C2672: 'f': no matching overloaded function found
Why does it not work as expected?
Upvotes: 1
Views: 238
Reputation: 62995
The problem is that you aren't forwarding a
or b
when recursively calling f
, which results in attempting to call the binary overload with a : int
and b : int&
. Here's a first step:
template<typename T>
T f(T&& a, T&& b) {
return a + b;
}
template<typename T, typename... Args>
T f(T&& a, T&& b, Args&&... args) {
return f(std::forward<T>(a), f(std::forward<T>(b), std::forward<Args>(args)...));
}
Now the problem is that all arguments passed in must have the same value category and any lvalue argument will cause an error, e.g. int i = 2; f(1, i, 3);
will fail. To fix this..:
template<typename T, typename U>
typename std::decay<T>::type
f(T&& a, U&& b) {
return a + b;
}
template<typename T, typename U, typename... Args>
typename std::decay<T>::type
f(T&& a, U&& b, Args&&... args) {
return f(std::forward<T>(a), f(std::forward<U>(b), std::forward<Args>(args)...));
}
which can then be simplified to:
template<typename T, typename U>
typename std::decay<T>::type
f(T&& a, U&& b) {
return a + b;
}
template<typename T, typename... Args>
typename std::decay<T>::type
f(T&& a, Args&&... args) {
return f(std::forward<T>(a), f(std::forward<Args>(args)...));
}
Upvotes: 6