c++ - std::function 的仅 move 版本

标签 c++ c++11 move-semantics

因为std::function是可复制的,标准要求用于构造它的可调用对象也是可复制的:

n337 (20.8.11.2.1)

template<class F> function(F f);

Requires: F shall be CopyConstructible. f shall be Callable (20.8.11.2) for argument types ArgTypes and return type R. The copy constructor and destructor of A shall not throw exceptions.`

这意味着不可能形成 std::function来自不可复制的绑定(bind)对象或捕获仅 move 类型的 lambda,例如 std::unique_ptr .

似乎可以为只 move 的可调用对象实现这样的只 move 包装器。 std::function 是否有标准库仅 move 等效项?或者,是否有针对此问题的通用解决方法?

最佳答案

不,std::function 没有只能 move 的版本在 C++ std图书馆。 (从 C++14 开始)

Fastest possible delegatesstd::function 的实现像恰好比大多数 std::function 更快的类许多 std 中的实现库,并且应该很容易 fork 成 movecopy版本。

包装您的move仅将函数对象转换为 shared_ptr<F>在一个有转发的类中 operator()是另一种方法。

这里是 task草图:

template<class Sig>
struct task;

namespace details {
  template<class Sig>
  struct task_iimpl;
  template<class R, class...Args>
  struct task_iimpl<R(Args...)> {
    virtual ~task_iimpl() {}
    virtual R invoke(Args&&...args) const = 0;
  };
  template<class F, class Sig>
  struct task_impl;
  template<class F, class R, class...Args>
  struct task_impl<F,R(Args...)>:
    task_iimpl<R(Args...)>
  {
    F f;
    template<class T>
    task_impl(T&& t):f(std::forward<T>(t)) {}
    virtual R invoke(Args&&...args) const override {
      return f( std::forward<Args>(args...) );
    }
  };
  template<class F, class...Args>
  struct task_impl<F,void(Args...)>:
    task_iimpl<void(Args...)>
  {
    F f;
    template<class T>
    task_impl(T&& t):f(std::forward<T>(t)) {}
    virtual void invoke(Args&&...args) const override {
      f( std::forward<Args>(args...) );
    }
  };
}
template<class R, class...Args>
struct task<R(Args...)> {
  virtual ~task_iimpl() {}
  R operator()(Args...args) const {
    return pImpl->invoke(std::forward<Args>(args...));
  }
  explicit operator bool()const{ return static_cast<bool>(pImpl); }
  task(task &&)=default;
  task& operator=(task &&)=default;
  task()=default;

  // and now for a mess of constructors
  // the rule is that a task can be constructed from anything
  // callable<R(Args...)>, destroyable, and can be constructed
  // from whatever is passed in.  The callable feature is tested for
  // in addition, if constructed from something convertible to `bool`,
  // then if that test fails we construct an empty task.  This makes us work
  // well with empty std::functions and function pointers and other tasks
  // that are call-compatible, but not exactly the same:
  struct from_func_t {};
  template<class F,
    class dF=std::decay_t<F>,
    class=std::enable_if_t<!std::is_same<dF, task>{}>,
    class FR=decltype(std::declval<F const&>()(std::declval<Args>()...)),
    std::enable_if_t<std::is_same<R, void>{} || std::is_convertible<FR, R>{} >*=0,
    std::enable_if_t<std::is_convertible<dF, bool>{}>*=0
  >
  task(F&& f):
    task(
      static_cast<bool>(f)?
      task( from_func_t{}, std::forward<F>(f) ):
      task()
    )
  {}
  template<class F,
    class dF=std::decay_t<F>,
    class=std::enable_if_t<!std::is_same<dF, task>{}>,
    class FR=decltype(std::declval<F const&>()(std::declval<Args>()...)),
    std::enable_if_t<std::is_same<R, void>{} || std::is_convertible<FR, R>{} >*=0,
    std::enable_if_t<!std::is_convertible<dF, bool>{}>*=0
  >
  task(F&& f):
    task( from_func_t{}, std::forward<F>(f) )
  {}

  task(std::nullptr_t):task() {}
  // overload resolution helper when signatures match exactly:
  task( R(*pf)(Args...) ):
    task( pf?task( from_func_t{}, pf ):task() )
  {}
private:
  template<class F,
    class dF=std::decay_t<F>
  >
  task(from_func_t, F&& f):
    pImpl( std::make_unique<details::task_impl<dF,R(Args...)>>(
      std::forward<F>(f)
    )
  {}

  std::unique_ptr<details::task_iimpl<R(Args...)> pImpl;
};

但它没有经过测试或编译,我只是写了它。

更工业化的版本将包括一个小型缓冲区优化 (SBO) 来存储小型可调用对象(假设它们是可 move 的;如果不可 move ,则存储在堆上以允许 move ),以及一个 get-pointer-if-you-guess -the-type-right(如 std::function )。

关于c++ - std::function 的仅 move 版本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25330716/

相关文章:

c++ - C++ 中的高效整数下限函数

c++模板来更改函数的constness

c++ - 延迟构造的 shared_ptr

c++11 - C++0x 中的最终虚函数

c++ - 局部变量的右值引用和 move

c++ - 如何使用 gdb 查找 g++ 代码中的浮点异常

c++ - 显式实例化

c++ - IEEE 浮点标准的 (+0)+(-0) 是什么?

c++ - move 构造函数问题

c++ - 我是否会受益于应用 move 语义或将对以字符串形式返回文件内容的函数执行返回值优化?