is any difference between std::forward and std::forward?

前端 未结 2 1704
天涯浪人
天涯浪人 2020-12-15 05:33

are these functions equivalent?

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

template 
void foo2(         


        
相关标签:
2条回答
  • 2020-12-15 06:21

    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).

    0 讨论(0)
  • 2020-12-15 06:23

    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)); 
        };
    }
    
    0 讨论(0)
提交回复
热议问题