加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

应用C 11将语义移动到绑定函数

发布时间:2020-12-16 06:52:35 所属栏目:百科 来源:网络整理
导读:我有一些现有的C 98代码,它使用boost :: function和boost:bind进行异步回调.代码的一些相关简化片段包括: typedef boost::functionvoid (boost::system::error_code,size_t) WriteHandler;struct WriteOperation{ WriteOperation(const boost::shared_ptrI
我有一些现有的C 98代码,它使用boost :: function和boost:bind进行异步回调.代码的一些相关简化片段包括:

typedef boost::function<void (boost::system::error_code,size_t)> WriteHandler;

struct WriteOperation
{
    WriteOperation(const boost::shared_ptr<IDevice>& device,const std::string& data,const WriteHandler& handler)
        : m_Device(device),m_Data(data),m_Handler(handler) {}

private:
    boost::shared_ptr<IDevice> m_Device;
    std::string m_Data;
    WriteHandler m_Handler;

    void Complete()
    {
        boost::system::error_code ec;
        size_t len;
        ...
        Async::Post(boost::bind(m_Handler,ec,len));
    }
};

struct Device : public IDevice
{
    void Write(const std::string& data,const WriteHandler& callback)
    {
        ...
        Async::Start(new WriteOperation(shared_from_this(),data,boost::bind(&Device::HandleWrite,this,handler,_1,_2)));
    }

 private:
    void HandleWrite(const WriteHandler& callback,boost::system::error_code ec,size_t len)
    {
        ...
        callback(ec,len);
    }
};

在构造WriteOperation时有一个必需的副本,但除此之外我试图避免副本,因为它们可能非常昂贵.

我在思考如何最好地写出C 11世界.显而易见的缺点是WriteOperation构造函数在内部将其参数复制到其字段中,因此应使用自动复制习惯用法:

WriteOperation(boost::shared_ptr<IDevice> device,std::string data,WriteHandler handler)
    : m_Device(std::move(device)),m_Data(std::move(data)),m_Handler(std::move(handler))
{}

(当然,裸新应该用unique_ptr替换,但这是一个副问题.)

但是,考虑到当前Device :: Write的实现,我认为这实际上并没有获得任何好处,因此也应该改变.我的问题是,我真的没有看到一个很好的方法来做到这一点.根据this advice,我有三个选择:

>声明多个重载(一个使用const&和一个使用&&) – 但由于这有两个参数,这两个参数都可以从移动语义中受益,这将需要四次重载 – 对于具有更多参数的方法,指数会更糟.此外,这会导致代码重复或将代码分散到其他方法上,这会影响可读性.
>按值传递并移动(类似于WriteOperation构造函数).当body正在复制时,这可能是最干净的选项,如果实际调用了WriteOperation构造函数,则这是正确的,但如果省略的部分包含可能在不构造WriteOperation的情况下返回的逻辑,该怎么办?在这种情况下,有一个浪费的副本.
>模板和完美的前进.这需要一个丑陋的SFINAE hack,它会混淆Intellisense并损害可读性(或者更糟糕的是,使参数类型不受约束),并要求将实现放入头中,这有时是不可取的.它会干扰类型转换,例如.一个SFINAE enable_if is_same查找std :: string将不接受const char * literal,而原始的const&版本会.

我错过了什么吗?有更好的解决方案吗?或者这只是移动语义没有任何区别的情况?

相关案例:

typedef boost::function<void (boost::system::error_code,const std::string&)> ReadHandler;

void Read(const ReadHandler& callback)
{
    ... boost::bind(&Device::HandleRead,callback,_2) ...
}

void HandleRead(const ReadHandler& callback,const std::string& data)
{
    ...
    callback(ec,data);
}

这一切看起来应该没问题,没有复制,也不需要移动语义.而且我不确定传递给Read的ReadHandler.

解决方法

按粗略顺序:

如果复制和移动一样昂贵,那么请使用const&amp ;.

如果您可靠地保留副本,并且移动便宜,则按价值计算.

如果做不到这一点,您可以将其填入标题中,并且可以使用sfinae或无约束模板,使用转发引用.

如果失败,如果参数数量有限,则写入每个重载.这是参数数量的2 ^ n,所以最好不要太多.在内部转发到基于转发参考的实现.

如果不这样做,你真的需要效率吗?

如果做不到这一点,请输入“T的创建者”.

template<class T,using Base=std::function<T()>>
struct creator_of: Base
{
  template<class U,std::enable_if_t<std::is_constructible<T,U&&>{},int> =0
  >
  creator_of(U&&u):
    Base([&]()->T{ return std::forward<U>(u); })
  {}
  template<class U,std::result_of_t<std::decay_t<U>()>{},int> =0
  >
  creator_of(U&&u):
    Base(std::forward<U>(u))
  {}

  creator_of(creator_of&&)=default;
  creator_of():
    Base([]()->T{return {};}}
  {}
};

根据需要增加. creator_of< std :: string>可以从可以构造std :: string的东西构建,也可以从返回std :: string的函数对象构造.

在内部你可以调用()一次.

(代码未编译,但设计合理.)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读