转发可变参数列表

3

以下两段代码都可以编译并按预期运行,它们有什么不同吗?

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

看着SO上的如何在可变参数函数中调用std::forward?,第二种方法似乎被推荐,但第一种方法不是也能实现同样的功能吗?

1个回答

3

它们并不相同。当 args 的元数为 0 或 1 时,它们相同。否则,它将无法编译,需要考虑......

#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;
}

演示

对于失败的情况,std::forward<U...>(args...) 展开成 forward<int, int>(int&, int&) 并且会编译失败。

std::forward<U>(args)... 展开成 std::forward<int>(int&),std::forward<int>(int&)


所以forward只能接受一个模板参数? - Sridhar Thiagarajan
是的,正确的,请看这里 -> https://zh.cppreference.com/w/cpp/utility/forward - rmawatson
既然你正在传递一个临时对象,那么它不应该扩展为forward<int,int>(int &&,int &&),我是否误解了? - Sridhar Thiagarajan
现在它是一个命名的临时变量。在time_function内,所有的整数都是args参数包的一部分。这就是std::forward的全部意义。在这种情况下,它将返回int&&。 - rmawatson
啊,关于模板参数类型,它不应该是int&&吗?据我理解,std::forward根据模板推断类型来判断是否进行转换。 - Sridhar Thiagarajan
1
这可能会澄清正在发生的事情。下面示例中的重要一点是,U在每种情况下都不仅仅是'int',如果它是一个左值,它将是int&并且引用折叠规则适用https://ideone.com/cfK0cb。这应该让您感受到'std :: forward知道是否进行转换'的方式。 - rmawatson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接