Search code examples
c++c++11templatesc++14perfect-forwarding

Forwarding variadic list of arguments


Both of the following code compiles and performs as expected, are they different?

template<typename T, typename ...U>
auto time_function(T&& func, U&& ...args)
{
   std::cout << "timing" << std::endl;
   auto val = std::forward<T>(func)(std::forward<U...>(args...));
   std::cout << "timing over" << std::endl;
   return val;
}

template<typename T, typename ...U>
auto time_function(T&& func, U&& ...args)
{
   std::cout << "timing" << std::endl;
   auto val = std::forward<T>(func)(std::forward<U>(args)...);
   std::cout << "timing over" << std::endl;
   return val;
}

Looking at SO How would one call std::forward on all arguments in a variadic function?, second seems to be recommended, but doesn't the first do the same thing?


Solution

  • They are not the same. They are the same in the case that the arity of args is 1 or 0. otherwise it will fail to compile, consider..

    #include <iostream>
    using namespace std;
    template<typename T, typename ...U>
    auto time_function_1(T&& func, U&& ...args)
    {
    
        std::cout<<"timing"<<std::endl;
        auto val = std::forward<T>(func)(std::forward<U...>(args...));
        std::cout<<"timing over"<<std::endl;
        return val;
    }
    
        template<typename T, typename ...U>
    auto time_function_2(T&& func, U&& ...args)
    {
    
        std::cout<<"timing"<<std::endl;
        auto val = std::forward<T>(func)(std::forward<U>(args)...);
        std::cout<<"timing over"<<std::endl;
        return val;
    }
    
    
    
    int f (int){return 0;}
    
    int y (int,int){return 0;}
    
    int main() {
        time_function_1(f,1);
        time_function_2(f,1);
    
        time_function_1(y,1,2); // fail
        time_function_2(y,1,2);
        return 0;
    }
    

    Demo

    for the failing case std::forward<U...>(args...) expands to forward<int, int>(int&, int&) and will fail to compile.

    std::forward<U>(args)... expands to std::forward<int>(int&),std::forward<int>(int&)