为什么递归可变参数模板不能按预期工作?

xml*_*lmx 1 c++ recursion templates variadic-templates c++11

#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);
}
Run Code Online (Sandbox Code Playgroud)

VS 2015输出:错误C2672:'f':未找到匹配的重载功能

为什么它不能按预期工作?

ild*_*arn 6

问题是你没有转发a或b递归调用f,这导致尝试用a : int和调用二进制重载b : int&.这是第一步:

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)...));
}
Run Code Online (Sandbox Code Playgroud)

现在问题是传入的所有参数必须具有相同的值类别,并且任何lvalue参数都将导致错误,例如int i = 2; f(1, i, 3);将失败.解决这个问题..:

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)...));
}
Run Code Online (Sandbox Code Playgroud)

然后可以简化为:

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)...));
}
Run Code Online (Sandbox Code Playgroud)