转发参考始终视为右值参考

时间:2018-08-27 17:23:14

标签: c++ c++11

所以我有一些“复杂的”代码,看起来像这样:

namespace details {

template <typename T>
T do_smth_impl (T&& v) {
    // process
    return std::move (v);
}

}

template <typename T>
T do_smth (T v) {
    return details::do_smth_impl (std::move (v));
}

details::do_smth_impl()采用转发参考,但是由于它位于details命名空间中,并且仅用作实现细节(在这种情况下,不需要在其他功能中使用它,但是我确实需要因为有多个处理不同类型的do_smth_impl()函数而将其分开),而且我确实确定只有rvalue引用将传递给impl函数,是否需要返回std::forward<T> (v)?< / p>

2 个答案:

答案 0 :(得分:6)

forward。有一天,某人(也许是您!)会向do_smth_impl()添加一个调用,并给它一个左值,然后该调用将编译,突然您的左值会从您的期望中移出。您将花一些时间对其进行调试,然后将其更改为forward。写std::move胜过std::forward<T>根本没有好处(我认为较低的字符数没有好处)。

如果您真的打算将此函数接受rvalue,则应在其界面中使其明确。要么SFINAE:

template <typename T, std::enable_if_t<!std::is_reference<T>::value, int> = 0>
void do_smth_impl(T&&);

static_assert

template <typename T>
void do_smth_impl(T&&) {
    // there are lots of ways to spell this
    static_assert(std::is_rvalue_reference<T&&>::value, "rvalues only");
    static_assert(!std::is_lvalue_reference<T>::value, "!");
    static_assert(!std::is_lvalue_reference<T&&>::value, "!");
    static_assert(!std::is_reference<T>::value, "!");
}

这将使您的假设调用具有左值不编译。与编译和执行错误的操作相比,编译失败是更好的选择。然后,也许在那个呼叫站点,您可以花些时间认真考虑是否要向该函数传递左值。也许传递左值是一个错误,现在您抓住了它!

但是将功能保持不变,从转发引用中执行move只是在麻烦。

答案 1 :(得分:0)

如果在很多地方需要这种要求,则可以使用下一种技术:

template <typename T, typename = typename std::enable_if<std::is_rvalue_reference<T&&>::value>::type>
using require_rvalue = T&&;

template <typename T>
void do_smth_impl(require_rvalue<T> val) {
    ...
}