是什么区别std :: forward <t>和std :: forward <decltype(t)>?</decltype(t)> </t>

时间:2014-04-27 08:19:45

标签: c++ c++11 perfect-forwarding

这些功能是否相同?

template <class T>
void foo(T && t)
{
    bar(std::forward<T>(t));
}

template <class T>
void foo2(T && t)
{
    bar(std::forward<decltype(t)>(t));
}

template <class T>
void foo3(T && t)
{
    bar(std::forward(t));
}

如果是,我可以一直使用这个宏来完美转发吗?

#define MY_FORWARD(var) std::forward<decltype(var)>(var)

或只是使用

bar(std::forward(t));

我相信foo2foo3相同,但我发现人们总是像foo那样使用前进,是否有理由明确写出类型?

我了解TT&&是两种不同的类型,但我认为std::forward<T>std::forward<T&&>总是给出相同的结果?


编辑:

我想使用宏的原因是我想在下面的C ++ 1y代码中保存一些输入,我在不同的地方有很多类似的代码

#define XLC_FORWARD_CAPTURE(var) var(std::forward<decltype(var)>(var))
#define XLC_MOVE_CAPTURE(var) var(std::move(var))

template <class T, class U>
auto foo(T && func, U && para )
{
    auto val = // some calculation
    return [XLC_FORWARD_CAPTURE(func),
            XLC_FORWARD_CAPTURE(para),
            XLC_MOVE_CAPTURE(val)](){
              // some code use val
              func(std::forward<U>(para)); 
          };
}

2 个答案:

答案 0 :(得分:16)

  

这些功能两个等效吗?

,它们是等效的。 decltype(t)T&&相同,与std::forward一起使用时,TT&&之间没有区别,无论T是什么

  

我是否可以始终使用此宏进行完美转发?

是的,你可以。如果您想使代码不可读且不可维护,那么请执行此操作。但我强烈建议不要这样做。一方面,你使用这个宏基本上没什么收获。而另一方面,其他开发人员必须查看定义才能理解它,并且可能导致细微的错误。例如,添加额外的括号不会起作用:

MY_FORWARD((t))

相比之下,decltype的表单完全有效。特别是,它是从通用lambda表达式转发参数的首选方法,因为没有显式类型参数:

[](auto&& t) { foobar(std::forward<decltype(t)>(t)); }

我使用std::forward(t)忽略了第3个变体,因为它无效。


更新:关于您的示例:您可以使用按值调用而不是按引用调用作为函数模板{ {1}}。然后,您可以使用foo代替std::move。这为代码添加了两个额外的移动,但没有额外的复制操作。另一方面,代码变得更清晰:

std::forward

答案 1 :(得分:1)

接受的答案不能完全解决标题中的问题。

宏参数保留表达式的类型。模板中的转发参数没有。这意味着t中的foo2(作为转发函数参数)的类型为T&&(因为这是转发模板参数),但是当宏位于另一个时,它可能有所不同。上下文。例如:

using T = int;
T a = 42;
T&& t(std::move(a));
foo(MY_FORWARD(t)); // Which foo is instantiated?

请注意,t不是xem值but an lvalue。使用std::forward<T>(t)(等效于std::forward<int>(t)),t将作为左值转发。但是,与MY_FORWARD(t)等效的std::forward<int&&>(t)t将作为xvalue转发。当您必须处理带有右值引用类型的某些声明的变量时,有时会需要这种上下文相关的差异(即使语法看起来相似,也不要转发参数)。