简体   繁体   English

是std :: forward之间的任何区别 <T> 和std :: forward <decltype(t)> ?

[英]is any difference between std::forward<T> and std::forward<decltype(t)>?

are these functions equivalent? 这些功能相同吗?

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

if they are, can I always use this macro for perfect forwarding? 如果是,我可以一直使用这个宏来完美转发吗?

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

or just use 或者只是使用

bar(std::forward(t));

I believe foo2 and foo3 are same, but I found people are always use forward like foo , is any reason to explicitly write the type? 我相信foo2foo3是一样的,但我发现人们总是像foo一样使用前进,是否有任何理由明确写出类型?

I understand that T and T&& are two different types, but I think std::forward<T> and std::forward<T&&> always give the same result? 我知道TT&&是两种不同的类型,但我认为std::forward<T>std::forward<T&&>总是给出相同的结果?


Edit: 编辑:

the reason I want to use macro is I want to save some typing on following C++1y code, I have many similar code in different places 我想使用宏的原因是我想在以下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)); 
          };
}

Are these functions two equivalent? 这些功能是两个相同的吗?

Yes , they are equivalent. 是的 ,它们是等价的。 decltype(t) is the same as T&& , and when used with std::forward , there is no difference between T and T&& , regardless what T is. decltype(t)T&&相同,当与std::forwardTT&&之间没有区别,无论T是什么。

Can I always use this macro for perfect forwarding? 我可以一直使用此宏来完美转发吗?

Yes, you can. 是的你可以。 If you want to make your code unreadable and unmaintainable, then do so. 如果您想使代码不可读且不可维护,那么请执行此操作。 But I strongly advise against it. 但我强烈建议不要这样做。 On the one hand, you gain basically nothing from using this macro. 一方面,你使用这个宏基本上没什么收获。 And on the other hand, other developers have to take a look at the definition to understand it, and it can result in subtle errors. 而另一方面,其他开发人员必须查看定义才能理解它,并且可能导致细微的错误。 For example adding additional parentheses won't work: 例如,添加额外的括号将无效:

MY_FORWARD((t))

In contrast, the form with decltype is perfectly valid. 相反,具有decltype的形式是完全有效的。 In particular, it is the preferred way of forwarding parameters from generic lambda expressions, because there are no explicit type parameters: 特别是,它是从通用lambda表达式转发参数的首选方法,因为没有显式类型参数:

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

I ignored the 3rd variant with std::forward(t) , because it isn't valid. 我用std::forward(t)忽略了第3个变种,因为它无效。


Update: Regarding your example: You can use call-by-value instead of call-by-reference for the function template foo . 更新:关于您的示例:您可以使用call-by-value而不是函数模板foocall-by-reference Then you can use std::move instead of std::forward . 然后你可以使用std::move而不是std::forward This adds two additional moves to the code, but no additional copy operations. 这为代码添加了两个额外的移动,但没有额外的复制操作。 On the other hand, the code becomes much cleaner: 另一方面,代码变得更清晰:

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

The accepted answer does not solve the problem in title completely. 接受的答案并没有完全解决标题中的问题。

A macro argument preserves the type of the expression. 宏参数保留表达式的类型。 A forwarding parameter in a template does not. 模板中的转发参数不会。 This means t in foo2 (as a forwarding function parameter) has the type T&& (because this is the forwarding template parameter), but it can be something different when the macro is in other contexts. 这意味着foo2 t (作为转发函数参数)具有类型T&& (因为这是转发模板参数),但是当宏处于其他上下文中时它可能是不同的。 For example: 例如:

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

Note here t is not an xvalue, but an lvalue . 注意这里t 不是 t 而是左值 With std::forward<T>(t) , which is equivalent to std::forward<int>(t) , t would be forwarded as an lvalue. 使用std::forward<T>(t) ,它等同于std::forward<int>(t)t将作为左值转发。 However, with MY_FORWARD(t) , which is equivalent to std::forward<int&&>(t) , t would be forwarded as an xvalue. 但是,使用MY_FORWARD(t) ,它相当于std::forward<int&&>(t)t将作为xvalue转发。 This contextual-dependent difference is sometime desired when you have to deal with some declared variables with rvalue reference types (not forwarding paramter even they may look like similar in syntax). 当您必须使用rvalue引用类型处理一些声明的变量时,这种依赖于上下文的差异有时是需要的(即使它们在语法上看起来类似,也不会转发参数)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM