Move-only version of std::function

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.


Yes, there is a proposal for std::move_only_function in the current draft of C++23, adopted 2021-10:

This paper proposes a conservative, move-only equivalent of std::function.

See also the cppreference entry on std::move_only_function:

Class template std::move_only_function is a general-purpose polymorphic function wrapper. std::move_only_function objects can store and invoke any constructible (not required to be move constructible) Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to member objects.
...
std::move_only_function satisfies the requirements of MoveConstructible and MoveAssignable, but does not satisfy CopyConstructible or CopyAssignable.