如何正确使用通过转发参考传递的可调用项? [英] How do correctly use a callable passed through forwarding reference?

查看:122
本文介绍了如何正确使用通过转发参考传递的可调用项?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我习惯于将lambda函数(和其他可调用对象)传递给模板函数-并按如下所述使用它们

I'm used to pass lambda functions (and other callables) to template functions -- and use them -- as follows

template <typename F>
auto foo (F && f)
 {
   // ...

   auto x = std::forward<F>(f)(/* some arguments */);

   // ... 
 }

我的意思是:我习惯于将它们通过转发引用传递,并称为通过std::forward传递.

I mean: I'm used to pass them through a forwarding reference and call them passing through std::forward.

另一位Stack Overflow用户认为(请参见对此答案的评论),此功能调用了两次或更多次,这很危险,因为在使用r值引用调用该函数时,它在语义上是无效的,并且有潜在的危险(甚至还有未定义的行为).

Another Stack Overflow user argue (see comments to this answer) that this, calling the functional two or more time, it's dangerous because it's semantically invalid and potentially dangerous (and maybe also Undefined Behavior) when the function is called with a r-value reference.

我已经部分地误解了他的意思(我的错),但剩下的疑问是下面的bar()函数(在同一对象上具有不可数的多个std::forward)是正确的代码还是(也许是唯一的)代码危险的.

I've partially misunderstand what he means (my fault) but the remaining doubt is if the following bar() function (with an indubitable multiple std::forward over the same object) it's correct code or it's (maybe only potentially) dangerous.

template <typename F>
auto bar (F && f)
 {
   using A = typename decltype(std::function{std::forward<F>(f)})::result_type;

   std::vector<A>  vect;

   for ( auto i { 0u }; i < 10u ; ++i )
      vect.push_back(std::forward<F>(f)());

   return vect;
 }

推荐答案

在这种情况下,我认为一般规则适用.从变量中移动/转发变量后,您不应该对其进行任何处理,除非可以对其进行赋值.

I'd say the general rule applies in this case. You're not supposed to do anything with a variable after it was moved/forwarded from, except maybe assigning to it.

因此...

如何正确使用通过转发参考传递的可调用项?

How do correctly use a callable passed through forwarding reference?

仅当您确定不会再被调用时(即,如果有话,在最后一次通话时),才向前转发.

Only forward if you're sure it won't be called again (i.e. on last call, if at all).

如果从未调用过一次,则没有理由不转发.

If it's never called more than once, there is no reason to not forward.

关于您的摘要为何如此危险的原因,请考虑使用仿函数:

As for why your snippet could be dangerous, consider following functor:

template <typename T>
struct foo
{
    T value;
    const T &operator()() const & {return value;}
    T &&operator()() && {return std::move(value);}
};

作为优化,operator()在调用右值时允许调用者从value移出.

As an optimization, operator() when called on an rvalue allows caller to move from value.

现在,如果给定此函子,则模板将无法编译(因为正如T.C.所说,std::function在这种情况下将无法确定返回类型).

Now, your template wouldn't compile if given this functor (because, as T.C. said, std::function wouldn't be able to determine return type in this case).

但是如果我们稍作改动:

But if we changed it a bit:

template <typename A, typename F>
auto bar (F && f)
 {    
   std::vector<A>  vect;

   for ( auto i { 0u }; i < 10u ; ++i )
      vect.push_back(std::forward<F>(f)());

   return vect;
 }

然后,给定该仿函数,它会突然破裂.

then it would break spectacularly when given this functor.

这篇关于如何正确使用通过转发参考传递的可调用项?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆