代码之家  ›  专栏  ›  技术社区  ›  allo

如何使用(lambda)函数填充C++容器?

  •  9
  • allo  · 技术社区  · 6 年前

    我想用指向对象的指针初始化一个容器。我现在有一个这样的循环:

    for(int i=0;i < n;i++) {
        container.push_back(new Object());
    }
    

    哪个C++操作(即类似于 std::transform )是否有权替换此循环并用 n 新创建的对象?

    3 回复  |  直到 6 年前
        1
  •  8
  •   Aconcagua    6 年前

    使用 std::generate :

    constexpr int n = 10;
    std::vector<Object*> v1(n);
    std::generate(v1.begin(), v1.end(), [](){ return new Object(); });
    

    std::generate_n 以下内容:

    std::vector<Object*> v2;
    v2.reserve(n); // pre-allocate sufficient memory to prevent re-allocations
                   // (you should have done in original loop approach as well)
    std::generate_n(std::back_inserter(v2), n, [] { return new Object(); });
    
        2
  •  5
  •   songyuanyao    6 年前

    你可以用 std::generate_n std::back_inserter 和兰姆达。

    std::generate_n(std::back_inserter(container), n, [] { return new Object(); });
    
        3
  •  0
  •   Yakk - Adam Nevraumont    6 年前

    目标是这样的语法:

    std::vector<Object*> v1 = generate([](auto&&){ return new Object; }, 10).make_container();
    

    我们说要用一个特定的lambda生成10个元素,然后创建一个请求类型的容器。

    它需要一些样板。首先,一个计算并调用函数的输入迭代器:

    template<class F>
    struct generator_iterator {
      F f;
      std::size_t i = 0;
    
      using self=generator_iterator;
      friend bool operator==(self const& lhs, self const& rhs){ return lhs.i==rhs.i; }
      friend bool operator!=(self const& lhs, self const& rhs){ return lhs.i!=rhs.i; }
      using reference=std::result_of_t<F const&(std::size_t const&)>;
      using value_type=std::decay_t<reference>;
      using difference_type=std::ptrdiff_t;
      using pointer=value_type*;
      using iterator_category=std::input_iterator_tag;
    
      self& operator++(){++i; return *this;}
      self operator++(int){auto tmp=*this; ++*this; return tmp;}
      reference operator*()const{ return f(i); }
      pointer operator->()const { return std::addressof(f(i)); }
    
      friend difference_type operator-( self const& lhs, self const& rhs ) { return lhs.i-rhs.i; }
      self& operator-=( difference_type rhs )& {
        i-=rhs;
        return *this;
      }
      self& operator+=( difference_type rhs )& {
        i+=rhs;
        return *this;
      }
      friend difference_type operator+( self lhs, difference_type rhs ) {
        lhs += rhs;
        return lhs;
      }
      friend difference_type operator-( self lhs, difference_type rhs ) {
        lhs -= rhs;
        return lhs;
      }
    
    };
    

    接下来,一个range原语,带有 .make_container() 方法,通过显式或隐式传递类型,可以将范围转换为容器:

    template<class It>
    struct range_t {
      It b, e;
      It begin() const { return b; }
      It end() const { return e; }
    
    private:
      struct container_maker {
        range_t const* self;
        template<class C>
        operator C()&& {
          return {self->begin(), self->end()};
        }
      };
    public:
      container_maker make_container()const{
        return {this};
      }
      // C is optional
      template<class C>
      C make_container()const{
        return make_container();
      }
    };
    template<class It>
    range_t<It> range( It s, It f ) {
      return {std::move(s), std::move(f)};
    }
    

    然后我们把它们粘在一起:

    template<class F>
    auto generate( F&& f, std::size_t count ) {
      generator_iterator<std::decay_t<F>> e{f, count};
      generator_iterator<std::decay_t<F>> b{std::forward<F>(f)};
      return range( std::move(b), std::move(e) );
    }
    

    它汇编了:

    std::vector<object*>v1=生成([](auto&){返回新对象;},10).make_container();
    

    Live example 是的。