不,C++的std库中没有
std::function
的仅移动版本。(截至C++14)
Fastest possible delegates是一个类似于
std::function
的实现,它比许多
std
库中的
std::function
实现更快,并且应该很容易分叉成一个
move
和
copy
版本。
将您的仅移动函数对象包装到具有转发
operator()
的类中的
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;
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() {}
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),用于存储小型可调用对象(假设它们是可移动的;如果不可移动,则存储在堆上以允许移动),以及一个获取指针(如果你猜对了类型)的函数(例如
std::function
)。
std::function
在很多方面都存在问题,这个观点被普遍认可,但是要修复它却非常困难,因为这会破坏现有的代码。 - Kerrek SBfunction
执行类型擦除,因此是否可复制取决于该function
的实例在运行时是否可复制。 - dypconst
,而库要求这意味着线程安全。这使得那些想在并发环境中使用function<void()>
作为通用可调用对象的人们感到困难。另一个有些不成熟的方面是类型抹除分配器支持,特别是涉及花哨指针的部分;function
是该库中唯一具有类型抹除分配器且可复制的类。(有关一些方面,请参阅N3916。N4041也很有趣。) - Kerrek SBstd::any_invocable
(有时称为unique_function
),已经获得批准,但它不会出现在 C++20 中。 - Davis Herring