C++11 templated function with rvalue param call

淺唱寂寞╮ 提交于 2019-12-01 14:12:15
template<typename Args>
static void test2(Args&& args)
{ ... }

In the above function, even though the parameter type looks like an rvalue reference, it can bind to both rvalue and lvalue arguments. This is colloquially known as a universal reference. If the function argument is an rvalue of type U, then T is deduced as U, and T&& is U&&, an rvalue reference, which is straightforward. However, when the function argument is an lvalue of type U, then T will be deduced as U&, which means the function parameter type would be U& &&, which undergoes reference collapsing to become U&. However, for these special rules to apply, the type must be deduced.


O::test2(std::forward<Args>(args).value); // changed O.test2 to O::test2

In this case, the template parameter type is being deduced from the function argument. The argument itself is an lvalue, so the type of the function parameter args is also an lvalue.


O::template test2<t>(
    std::forward<t>(
        std::forward<Args>(args).value
    )
);

The difference here is that you've explicitly specified the template parameter type for test2. No deduction is taking place, and the function parameter is a simple rvalue reference in this case. It can only bind to rvalues, and you provide it this rvalue due to the outer std::forward<t> cast (here t = A). It has the same effect as static_cast<A&&>(value).


O::template test2<t>(
    std::forward<Args>(args).value
);

The last case should've explained why this doesn't work. As explained above, test2 can only bind to an rvalue in this case, and without the second std::forward from above, you're trying to bind an lvalue to an rvalue reference parameter, which fails.

tower120

Based on knowledge that objects, inside rvalue referenced object, also rvalue referenced. I decide to ended up with this (inspired by https://stackoverflow.com/a/24083200/1559666):

template<class T, class FieldT>
using addRefU = typename std::conditional<
                            std::is_rvalue_reference<T>::value,
                            typename std::add_rvalue_reference< FieldT >::type,
                            typename std::conditional<
                                std::is_rvalue_reference<FieldT>::value,
                                typename std::add_rvalue_reference< FieldT >::type,
                                typename std::add_lvalue_reference< FieldT >::type
                            >::type
                        >::type;

    T           T::value(FieldT)    resolve
------------------------------------------------------------
 rvalue         lvalue              rvalue
 rvalue         rvalue              rvalue
 lvalue         rvalue              rvalue
 lvalue         lvalue              lvalue

using t = addRefU<decltype(args), decltype(args.value)>;
O::template test2<t>(
    static_cast<t>(args.value)
);

http://coliru.stacked-crooked.com/a/40d10f5a2f45c288

Short enough, as for me.

P.S. If someone have some precautions about this, I would gladly listen to them.

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