web-dev-qa-db-ja.com

(ラムダ)関数を使用してC ++コンテナを埋める方法は?

オブジェクトへのポインタでコンテナを初期化したい。私は現在このようなループを持っています:

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

どのC++操作(つまり、std::transform)このループを置き換え、n新しく作成されたオブジェクトでコンテナを初期化する権利はありますか?

13
allo

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(); });
8
Ron

std::generate_n および std::back_inserter ラムダ付き。

std::generate_n(std::back_inserter(container), n, [] { return new Object(); });
5
songyuanyao

目標は次の構文です。

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

特定のラムダを使用して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;
  }

};
_

次に、範囲プリミティブと.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 = generate([](auto&&){ return new Object; }, 10).make_container();
_

実例