c++ - 如何传递一个non-copyable的函数对象给std::function?
天蓬老师
天蓬老师 2017-04-17 15:33:18
0
1
594
#include <memory>
#include <functional>

class A{    //non-copyable
    std::unique_ptr<int> a;
public:
    void operator()(){}    //non-const
};

void func(std::function<void(void)> f)
{}

int main()
{
    A fobj;
    func(fobj);
    return 0;
}

如上,需要传递一个A的函数对象给func,并且fobj不能是const型的。怎样实现呢?

天蓬老师
天蓬老师

欢迎选择我的课程,让我们一起见证您的进步~~

Antworte allen(1)
巴扎黑

有以下方案:

  • 用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;
}
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!