c++ - 如何传递一个non-copyable的函数对象给std::function?

 mobiledu2502856411 发布于 2022-11-01 01:46
#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型的。怎样实现呢?

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;
    }
    2022-11-12 01:43 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有