Because std::function
is copyable, the standard requires that callables used to construct it also be copyable:
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 typesArgTypes
and return typeR
. The copy constructor and destructor of A shall not throw exceptions.`
This implies that it is not possible to form an std::function
from a non-copyable bind object or a lambda that captured a move-only type such as std::unique_ptr
.
It seems possible to implement such a move-only wrapper for move-only callables. Is there a standard library move-only equivalent for std::function
or, is there a common workaround for this problem?
std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object. In particular, std::move produces an xvalue expression that identifies its argument t . It is exactly equivalent to a static_cast to an rvalue reference type.
std::move in C++ Moves the elements in the range [first,last] into the range beginning at result. The value of the elements in the [first,last] is transferred to the elements pointed by result. After the call, the elements in the range [first,last] are left in an unspecified but valid state.
You can recover the desired behavior by always using thread-local copies of the std::function because they'll each have an isolated copy of the state variables.
No, there is no move-only version of std::function
in the C++ std
library. (As of C++14)
Fastest possible delegates is an implementation of a std::function
like class that happens to be faster than most std::function
implementations in many std
libraries, and it should be easy to fork into a move
and copy
version.
Wrapping your move
only function object into a shared_ptr<F>
in a class with a forwarding operator()
is another approach.
Here is a task
sketch:
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; };
but it has not been tested or compiled, I just wrote it.
A more industrial strength version would include a small buffer optimization (SBO) to store small callables (assuming they are movable; if not movable, store on heap to allow moving), and a get-pointer-if-you-guess-the-type-right (like std::function
).
As others have pointed out, there is no move-only version of std::function
in the library. Following is a work-around that the reuses (abuses?) std::function
and allows it to accept move-only types. It is largely inspired by dyp's implementation in the comments, so a lot of the credit goes to him:
#include <functional> #include <iostream> #include <type_traits> #include <utility> template<typename T> class unique_function : public std::function<T> { template<typename Fn, typename En = void> struct wrapper; // specialization for CopyConstructible Fn template<typename Fn> struct wrapper<Fn, std::enable_if_t< std::is_copy_constructible<Fn>::value >> { Fn fn; template<typename... Args> auto operator()(Args&&... args) { return fn(std::forward<Args>(args)...); } }; // specialization for MoveConstructible-only Fn template<typename Fn> struct wrapper<Fn, std::enable_if_t< !std::is_copy_constructible<Fn>::value && std::is_move_constructible<Fn>::value >> { Fn fn; wrapper(Fn&& fn) : fn(std::forward<Fn>(fn)) { } wrapper(wrapper&&) = default; wrapper& operator=(wrapper&&) = default; // these two functions are instantiated by std::function // and are never called wrapper(const wrapper& rhs) : fn(const_cast<Fn&&>(rhs.fn)) { throw 0; } // hack to initialize fn for non-DefaultContructible types wrapper& operator=(wrapper&) { throw 0; } template<typename... Args> auto operator()(Args&&... args) { return fn(std::forward<Args>(args)...); } }; using base = std::function<T>; public: unique_function() noexcept = default; unique_function(std::nullptr_t) noexcept : base(nullptr) { } template<typename Fn> unique_function(Fn&& f) : base(wrapper<Fn>{ std::forward<Fn>(f) }) { } unique_function(unique_function&&) = default; unique_function& operator=(unique_function&&) = default; unique_function& operator=(std::nullptr_t) { base::operator=(nullptr); return *this; } template<typename Fn> unique_function& operator=(Fn&& f) { base::operator=(wrapper<Fn>{ std::forward<Fn>(f) }); return *this; } using base::operator(); }; using std::cout; using std::endl; struct move_only { move_only(std::size_t) { } move_only(move_only&&) = default; move_only& operator=(move_only&&) = default; move_only(move_only const&) = delete; move_only& operator=(move_only const&) = delete; void operator()() { cout << "move_only" << endl; } }; int main() { using fn = unique_function<void()>; fn f0; fn f1 { nullptr }; fn f2 { [](){ cout << "f2" << endl; } }; f2(); fn f3 { move_only(42) }; f3(); fn f4 { std::move(f2) }; f4(); f0 = std::move(f3); f0(); f0 = nullptr; f2 = [](){ cout << "new f2" << endl; }; f2(); f3 = move_only(69); f3(); return 0; }
Working version to coliru.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With