#include#include class A{ //non-copyable std::unique_ptr a; public: void operator()(){} //non-const }; void func(std::function f) {} int main() { A fobj; func(fobj); return 0; }
如上,需要传递一个A的函数对象给func,并且fobj不能是const型的。怎样实现呢?
有以下方案:
用A的引用。缺点:A被销毁时引用随之失效。
通过移动语义构造一个shared_ptr。缺点:额外的运行时开销,需要A可移动构造。
#include <memory> #include <functional> #include <utility> class A{ //non-copyable std::unique_ptr<int> a; public: void operator()(){} //non-const }; void func(std::function<void(void)> f) {} int main() { A obj; // by reference func([&obj](){obj();}); // by shared_ptr auto ptr = std::make_shared<A>(std::move(obj)); func([ptr](){(*ptr)();}); return 0; }
或者通过一个在拷贝时移动对象的wrapper来实现(需要A可移动构造):
#include <memory> #include <functional> #include <type_traits> class A{ //non-copyable std::unique_ptr<int> a; public: void operator()(){} //non-const }; void func(std::function<void(void)> f) {} template <class Fn, class Ret, class... Args> struct FunctionWrapperImpl { FunctionWrapperImpl(FunctionWrapperImpl &wrapper) : fn_(std::move(wrapper.fn_)) {} FunctionWrapperImpl(FunctionWrapperImpl &&wrapper) : fn_(std::move(wrapper.fn_)) {} FunctionWrapperImpl(Fn &&fn) : fn_(std::move(fn)) {} template <class T = Ret> std::enable_if_t<std::is_same<void, T>::value, Ret> operator()(Args... args) { fn_(std::forward<Args>(args)...); } template <class T = Ret> std::enable_if_t<!std::is_same<void, T>::value, Ret> operator()(Args... args) { return fn_(std::forward<Args>(args)...); } Fn fn_; }; template <class Fn> struct FunctionWrapper { FunctionWrapper(FunctionWrapper &&wrapper) : fn_(std::move(wrapper.fn_)) {} FunctionWrapper(Fn &&fn) : fn_(std::move(fn)) {} template <class Ret, class... Args> operator std::function<Ret(Args...)>() && { return std::function<Ret(Args...)>( FunctionWrapperImpl<Fn, Ret, Args...>(std::move(fn_))); } Fn fn_; }; template <class Fn> auto function_wrapper(Fn &&fn) { return FunctionWrapper<Fn>(std::move(fn)); } int main() { A obj; // function wrapper func(function_wrapper(std::move(obj))); return 0; }