简体   繁体   English

如何在std算法中使用unique_ptr的transform_iterator

[英]How to use transform_iterator of unique_ptr in std algorithm

I am trying to call lower_bound on transformed iterators of a vector<unique_ptr>>. 我试图在vector<unique_ptr>>.转换迭代器上调用lower_bound vector<unique_ptr>>. Similar questions had been asked previously on SO. 之前曾就SO问过同样的问题。 This one is slightly more complex that solutions to other problems are not readily applicable. 这个问题稍微复杂一些,其他问题的解决方案并不容易适用。

The problem is the same. 问题是一样的。 The std implementation calls unique_ptr operator= when it assigns __first to __middle during the search. 性病实现调用的unique_ptr运营商=当分配__first__middle在搜索过程中。 In this example, a list of transformed objects (int->double) are searched to locate the element equal to or greater than the input (double). 在此示例中,搜索变换对象列表(int-> double)以定位等于或大于输入(double)的元素。

int main ()
{
  vector<unique_ptr<int>>v {
    std::make_unique<int>(0),
    std::make_unique<int>(1),
    std::make_unique<int>(2),
    std::make_unique<int>(3),
    std::make_unique<int>(4),
  };

  auto transFunc = [](const unique_ptr<int>& m) -> double {
    return (*m) * 2.;
  }; 
  auto first = boost::make_transform_iterator(begin(v), transFunc);
  auto last = boost::make_transform_iterator(end(v), transFunc);  

  auto i = lower_bound(first, last, 5.);

  return 0;
}

I also tried using move_iterator's. 我也尝试过使用move_iterator。

  auto transFunc = [](unique_ptr<int>&& m) -> double {
    return (*m) * 2.;
  }; 
  auto first = boost::make_transform_iterator(
      make_move_iterator(begin(v)), transFunc);
  auto last = boost::make_transform_iterator(
      make_move_iterator(end(v)), transFunc);  

It seems like boost didn't carry the right-valueness forward in the transformed iterators. 似乎boost在转换的迭代器中没有带来正确的价值。

The code used to work in VS2013 but doesn't work in VS2015 or GNU. 该代码曾用于VS2013,但在VS2015或GNU中不起作用。

The lambda isn't copyable, and by default transform_iterator does retain a copy of the callable. lambda不可复制,默认情况下transform_iterator会保留可调用的副本。

Simple solution: std::ref or std::cref : 简单的解决方案: std::refstd::cref

Live On Coliru 住在Coliru

#include <memory>
#include <boost/iterator/transform_iterator.hpp>
#include <vector>

int main ()
{
    auto transFunc = [](const std::unique_ptr<int>& m) -> double { return (*m) * 2; }; 

    std::vector<std::unique_ptr<int>> v;
    v.push_back(std::make_unique<int>(0));
    v.push_back(std::make_unique<int>(1));
    v.push_back(std::make_unique<int>(2));
    v.push_back(std::make_unique<int>(3));
    v.push_back(std::make_unique<int>(4));

    auto first = boost::make_transform_iterator(begin(v), std::cref(transFunc));
    auto last  = boost::make_transform_iterator(end(v), std::cref(transFunc));  
    auto i = lower_bound(first, last, 5.);
}

Alternatively: 或者:

Create a copyable calleable instead: 改为创建一个可复制的calleable:

struct { double operator()(const std::unique_ptr<int>& m) const { return (*m) * 2; }; } transFunc;

Live On Coliru 住在Coliru

Bonus 奖金

Live On Coliru 住在Coliru

#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/phoenix.hpp>
#include <vector>
#include <memory>

using namespace boost::adaptors;
using namespace boost::phoenix::arg_names;

int main () {
    std::vector<std::unique_ptr<int>> v(5);
    boost::generate(v, [n=0]() mutable { return std::make_unique<int>(n++); });

    auto i = boost::lower_bound(
            v |
            indirected |
            transformed(2. * arg1), 5.);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM