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

时间:2016-12-21 10:34:35

标签: c++ c++17 perfect-forwarding 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>>>{});
}

为什么在调用带有参数元组的函数(f)来传递(t)时,我们不需要对元组的每个元素执行std::forward {{ 1}}在实现中?

2 个答案:

答案 0 :(得分:7)

您不需要std::forward每个元素因为std::get因元组的rvalue-reference和lvalue-reference而被重载。

std::forward<Tuple>(t)会为您提供左值(Tuple &)或右值(Tuple &&),根据您获得的结果,std::get会为您提供T & 1}}(左值)或T &&(右值)。查看std::get的各种重载。

有关std::tuplestd::get -

的一些详细信息

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

double a{0.0};
auto t1 = std::make_tuple(int(), a);
auto t2 = std::make_tuple(int(), double());

问题是 - 元组是否是左值?如果是,您可以移动其成员,如果不是,则必须复制,但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&&>{}, "");

回到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>&);

f的第一次通话中,a的类型将为int&&,因为tuple将转发为std::tuple<int>&&,而第二次转发int& case的类型为tuple,因为std::tuple<int>&将转发为 /** * Creates a new Vente entity. * * @Route("/new", name="vente_new") * @Method({"GET"}) */ public function newAction(Request $request) { $vente = new Vente(); $form = $this->createForm('AppBundle\Form\VenteType', $vente); return $this->render('vente/new.html.twig', array( 'vente' => $vente, 'form' => $form->createView(), )); }

答案 1 :(得分:2)

std::forward用于确保所有内容都以正确的值类别到达呼叫站点。

但元组的每个成员都是左值,即使它是rvalue个引用的元组。