只移动std :: function的版本
因为std::function
是可复制的,所以标准要求用于构造std :: function的可调用对象也是可复制的:
n337(20.8.11.2.1)
template<class F> function(F f);
要求:
F
应该是CopyConstructible。 对于参数typesArgTypes
和返回typesR
f
应为Callable(20.8.11.2)。 A的拷贝构造函数和析构函数不得抛出exception
这意味着不可能从不可复制的绑定对象或捕获只移动types(如unique_ptr)的lambda形成std :: function。
这似乎有可能实现这种只移动的可移动的可移动的包装。 是否有一个标准的库移动只相当于std ::函数? 或者,这个问题是否有一个共同的解决方法?
不,在C ++ std
库中没有移动版本的std::function
。 (从C ++ 14开始)
尽可能最快的代理是std::function
类的实现,它比许多std
库中的大多数std::function
实现要快,而且应该很容易分叉到一个move
和copy
版本。
用一个转发operator()
将一个只move
函数对象的函数对象封装到一个shared_ptr<F>
类中是另一种方法。
这是一个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; };
但没有经过testing或编译,我只是写了。
一个更具有工业强度的版本将包括一个小的缓冲区优化(SBO)来存储小可调参数(假设它们是可移动的;如果不能移动,则存储在堆上以允许移动),以及一个获取指针(如果你猜的话)types正确(如std::function
)。