Versión de solo movimiento de std :: function

Como std::function es copiable, el estándar requiere que los callables utilizados para construir std :: function también puedan ser copiados:

n337 (20.8.11.2.1)

template function(F f);

Requiere: F debe ser CopyConstructible. f debe ser invocable (20.8.11.2) para tipos de argumentos ArgTypes y return type R El constructor de copias y el destructor de A no lanzarán excepciones.

Esto implica que no es posible formar una función std :: a partir de un objeto de vinculación no copiable o una lambda que captura un tipo de solo movimiento como un único_ptr.

Parece posible implementar un contenedor de tan solo movimiento para call-only callables. ¿Existe un movimiento de biblioteca estándar, solo equivalente para std :: function? o, ¿hay una solución común para este problema?

No, no hay una versión de solo movimiento de std::function en la biblioteca estándar de C ++. (A partir de C ++ 14)

Los delegates más rápidos posibles son una implementación de una std::function como clase que resulta ser más rápida que la mayoría de las implementaciones std::function en muchas bibliotecas std , y debería ser fácil incluir una versión para move y copy .

Envolver su objeto de función move solo en un shared_ptr en una clase con un operator() reenvío operator() es otro enfoque.

Aquí hay un boceto de la task :

 template struct task; namespace details { template struct task_iimpl; template struct task_iimpl { virtual ~task_iimpl() {} virtual R invoke(Args&&...args) const = 0; }; template struct task_impl; template struct task_impl: task_iimpl { F f; template task_impl(T&& t):f(std::forward(t)) {} virtual R invoke(Args&&...args) const override { return f( std::forward(args...) ); } }; template struct task_impl: task_iimpl { F f; template task_impl(T&& t):f(std::forward(t)) {} virtual void invoke(Args&&...args) const override { f( std::forward(args...) ); } }; } template struct task { virtual ~task_iimpl() {} R operator()(Args...args) const { return pImpl->invoke(std::forward(args...)); } explicit operator bool()const{ return static_cast(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, 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=std::enable_if_t{}>, class FR=decltype(std::declval()(std::declval()...)), std::enable_if_t{} || std::is_convertible{} >*=0, std::enable_if_t{}>*=0 > task(F&& f): task( static_cast(f)? task( from_func_t{}, std::forward(f) ): task() ) {} template, class=std::enable_if_t{}>, class FR=decltype(std::declval()(std::declval()...)), std::enable_if_t{} || std::is_convertible{} >*=0, std::enable_if_t{}>*=0 > task(F&& f): task( from_func_t{}, std::forward(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 > task(from_func_t, F&& f): pImpl( std::make_unique>( std::forward(f) ) {} std::unique_ptr pImpl; }; 

pero no ha sido probado ni comstackdo, solo lo escribí.

Una versión de mayor resistencia industrial incluiría una pequeña optimización de buffer (SBO) para almacenar callables pequeños (suponiendo que sean móviles, si no móviles, almacenar en montón para permitir el movimiento), y un get-pointer-si-adivina-el- type-right (como std::function ).