std ::如何在没有显式std :: forward的情况下应用转发参数?

W.F*_*.F. 9 c++ perfect-forwarding c++17 stdapply

考虑可能的实施std::apply:

namespace detail {
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl(F &&f, Tuple &&t, std::index_sequence<I...>) 
{
    return std::invoke(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))...);
}
}  // namespace detail

template <class F, class Tuple>
constexpr decltype(auto) apply(F &&f, Tuple &&t) 
{
    return detail::apply_impl(
        std::forward<F>(f), std::forward<Tuple>(t),
        std::make_index_sequence<std::tuple_size_v<std::decay_t<Tuple>>>{});
}
Run Code Online (Sandbox Code Playgroud)

为什么在调用f带有参数元组的function()来传递(t)时,我们不需要在实现std::forward中对元组的每个元素std::get<I>(std::forward<Tuple>(t))...执行?

Hol*_*olt 7

您不需要std::forward每个元素,因为std::get重载了元组的rvalue-reference和lvalue-reference.

std::forward<Tuple>(t)会给你一个左值(Tuple &)或一个右值(Tuple &&),并根据你得到的,std::get给你一个T &(左值)或一个T &&(右值).看到各种过载std::get.


关于std::tuple和的一些细节std::get-

正如StoryTeller所提到的,元组的每个成员都是左值,无论它是由右值还是左值构造的,都与此无关:

double a{0.0};
auto t1 = std::make_tuple(int(), a);
auto t2 = std::make_tuple(int(), double());
Run Code Online (Sandbox Code Playgroud)

问题是 - 元组是否是左值?如果是,您可以移动其成员,如果不是,您必须复制,但std::get已经通过返回具有相应类别的成员来处理.

decltype(auto) a1 = std::get<0>(t1);
decltype(auto) a2 = std::get<0>(std::move(t1));

static_assert(std::is_same<decltype(a1), int&>{}, "");
static_assert(std::is_same<decltype(a2), int&&>{}, "");
Run Code Online (Sandbox Code Playgroud)

回到一个具体的例子std::forward:

template <typename Tuple>
void f(Tuple &&tuple) { // tuple is a forwarding reference
    decltype(auto) a = std::get<0>(std::forward<Tuple>(tuple));
}

f(std::make_tuple(int())); // Call f<std::tuple<int>>(std::tuple<int>&&);
std::tuple<int> t1;
f(t1); // Call f<std::tuple<int>&>(std::tuple<int>&);
Run Code Online (Sandbox Code Playgroud)

在第一次调用中f,类型aint&&因为tuple将被转发为a std::tuple<int>&&,而在第二种情况下其类型将int&因为tuple将被转发为a std::tuple<int>&.

  • @WF可能你应该稍微改变你的思维方式并将`std :: forward`视为条件`std :: move`,将`std :: move`视为普通演员,仅此而已.上面的答案,至少对我来说,难以解析,特别是*"你不能转发不是转发参考的东西"*部分 (5认同)
  • `你不能创建一个std :: tuple of reference`?那么什么是`std :: forward_as_tuple`呢? (2认同)
  • you never get a copy with `std::get`, what happens next depends on how the expression is used (2认同)