2016-07-27 12 views
0

私はクラスをレイジーなコンテナのように振る舞い、その場で値を生成します。その後、場合によっては値をフィルタリングしたいと思います。 Boost :: range :: adapters :: filteredはよく適しているようです。ただし、「範囲」への参照は保持されず、開始/終了イテレータのみが格納されます。boost :: filtersの範囲の寿命を延ばす

次のコードは、私のユースケースを模倣します。しかし、それは動作しません:containerは、rが使用される前に破壊されます。

#include <iostream> 
#include <vector> 

#include <boost/range/adaptor/filtered.hpp> 

#define PING() std::cerr << __PRETTY_FUNCTION__ << '\n' 

using ints = std::vector<int>; 

struct container 
{ 
    container() { PING(); } 
    ~container() { PING(); } 

    using value_type = typename ints::value_type; 

    using iterator = typename ints::iterator; 
    using const_iterator = typename ints::const_iterator; 

    iterator begin() { PING(); return std::begin(c_); } 
    iterator end() { PING(); return std::end(c_); } 

    const_iterator begin() const { PING(); return std::cbegin(c_); } 
    const_iterator end() const { PING(); return std::cend(c_); } 

    ints c_ = { 1, 2, 3, 4, 5 }; 
}; 

int main() 
{ 
    auto r = container{} | boost::adaptors::filtered([](auto&& v) { return v % 2; }); 
    std::cerr << "Loop\n"; 
    for (auto i: r) 
    std::cout << i << '\n'; 
} 

それは(live code)になり:

container::container() 
const_iterator container::begin() const 
const_iterator container::end() const 
const_iterator container::end() const 
const_iterator container::end() const 
container::~container() 
Loop 
1 
3 
5 

はみんながいる限り、私はそれを必要と住んでいることを保証するための簡単な方法はありますか?もちろんmainで変数を宣言してcontainer{}を格納することはできますが、実際にはこのコンテナが実際にはいくつかのオブジェクトを照会することで得られる実際の使用には不十分です。私はクライアント側がこれに対処しなければならないとは思わない。

範囲のコピーを保持するfilteredのいくつかのバージョンを書き直すのが最も簡単なようですが、あまりにも多くのコードを書き込まないようにするソリューションを探したいと思います。そして、私はRange-v2のソリューションを本当に探しています。Range-v3に依存するのは早すぎるかもしれません。

+0

コンテナの移動によってイテレータが無効になっていますか?そうでない場合は、これは簡単です。 – Yakk

+0

@Yakkコンテナを別のコンテナに移動するとどういう意味ですか?はい、それはイテレータを無効にします。それらは実際にはポインタのようなイテレータであり、インデックスではありません。 – akim

+0

ほとんどのコンテナは 'std :: array'と似ていません。他のコンテナへの' std :: move'がイテレータを動かすという点で、 'std :: vector'と似ています。そしてそれへのポインタ。 – Yakk

答えて

1

これは厄介です。

おもしろいことに、コンテナを最初にに保存しておき、パイプを保存したコンテナに適用してから、その範囲のようなふりをする必要があります。

template<class X>struct store{ X data; }; 
template<class Src, class Range> 
struct save_src_range: 
    private store<Src>, 
    Range 
{ 
    // boilerplate for copy/move goes here (TODO) 
    template<class S, class RangeFactory> 
    save_src_range(S&& s, RangeFactory&& f): 
    store<Src>{std::forward<S>(s)}, 
    Range(std::forward<RangeFactory>(f)(this->data)) 
    {} 
}; 

ここで、推論生成関数などで補完する必要があります。

次に、我々は既存の構文にその機能を挿入するための構文的にはかなりの方法が必要です。

我々はいくつかの柔道をやると、それは多分、連鎖した後、魔法のように動作させる
keep_a_copy(source) | boost::adapters::filter(... blah ...) 

一つのアプローチは次のようです。ある

それとも

source | keep_source_copy(boost::adapters::filter(... blah ...)) 

は少し簡単だと思います。

私はそれで刺しを取って、それは控えめに痛いですが、私は基本的に不可能何も表示されません。間違いなく、あまりにも多くのコードを書くことになります。

+0

ありがとう、私は実際にこれに似た何かで終わった。私はC++の範囲がそのような使用事例に対処することを願っています! – akim