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

纵饮孤独 提交于 2019-11-28 23:13:53

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.

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. In particular, it is the preferred way of forwarding parameters from generic lambda expressions, because there are no explicit type parameters:

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

I ignored the 3rd variant with std::forward(t), because it isn't valid.


Update: Regarding your example: You can use call-by-value instead of call-by-reference for the function template foo. Then you can use std::move instead of 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. 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. With std::forward<T>(t), which is equivalent to std::forward<int>(t), t would be forwarded as an lvalue. However, with MY_FORWARD(t), which is equivalent to std::forward<int&&>(t), t would be forwarded as an 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).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!