私は、このソリューションに大まかに基づいて、一連のn次元デカルト積クラスに取り組んでいます。
同じ基本的なアルゴリズムのセットに対してさまざまなデータ型があり、「ああ!テンプレートを使用して全体的な作業を減らす」と思いました。そして、これまで、それは素晴らしい働きをしてきました。Boostのiterator_facadeを使用しています。
私の問題は、で動作するように作成した派生クラスにありmap<char, boost::integer_range<int> >
ます。反復ごとにが生成map<char,int>
されますが、アルゴリズムに関する限り、スペースが無駄になっているため、2番目の値が0のペアは除外します。
派生クラスは、イテレータの戻り値を生成する関数をオーバーロードし、機能します。ただし、最初の反復中に、基本クラスのジェネレーターが呼び出されます。私はとても混乱しています。誰かアイデアはありますか?
関連するコードスニペットは次のとおりです。
#include <boost/container/flat_map.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/range/irange.hpp>
#include <utility>
#include <iostream>
using namespace boost;
using namespace boost::tuples;
using namespace std;
template <class Container2DMap,
class return_type = boost::container::flat_map<typename Container2DMap::value_type::first_type,
typename Container2DMap::value_type::second_type::value_type> >
class CartProductIterator2DMap : public boost::iterator_facade<
CartProductIterator2DMap<Container2DMap, return_type>,
const return_type,
boost::forward_traversal_tag> {
public:
typedef typename Container2DMap::value_type::first_type first_type;
typedef typename Container2DMap::const_iterator first_iterator;
typedef typename Container2DMap::value_type::second_type::value_type second_type;
typedef typename Container2DMap::value_type::second_type::const_iterator second_iterator;
CartProductIterator2DMap(const Container2DMap &container) {
rangeIterSetup(container);
}
CartProductIterator2DMap() : _finished(true) {}
virtual ~CartProductIterator2DMap() {}
private:
virtual bool equal(const CartProductIterator2DMap &other) const {
if (_finished || other._finished) {
if (_finished && other._finished) {
return true;
} else {
return false;
}
} else if (_currentIter == other._currentIter) {
return true;
} else {
return false;
}
}
virtual void increment() { advance(); }
virtual void advance() {
advanceIter();
}
virtual const return_type& dereference() const { return _currentIter; }
protected:
struct mode {
const static bool stopIter = false;
const static bool continueIter = true;
};
typedef boost::tuple<second_iterator,
second_iterator,
second_iterator> SecondIterDescription;
typedef boost::container::flat_map<first_type, SecondIterDescription> RangeIterMap;
friend class boost::iterator_core_access;
return_type _currentIter;
RangeIterMap _rangeIter;
bool _finished;
bool _iterMode;
virtual void advanceIter() {
if (_iterMode == mode::continueIter) {
_currentIter = genReturnValue(_rangeIter);
_iterMode = advanceRangeIter(_rangeIter);
} else {
_finished = true;
}
}
virtual void rangeIterSetup(const Container2DMap &container) {
_finished = false;
if (container.empty()) {
_iterMode = mode::stopIter;
} else {
_iterMode = mode::continueIter;
for (typename Container2DMap::const_iterator it = container.begin();
it != container.end(); ++it) {
_rangeIter.insert(
make_pair(it->first,
SecondIterDescription(it->second.begin(), it->second.end(), it->second.begin())
)
);
}
advance();
}
}
virtual return_type genReturnValue(const RangeIterMap &rangeIter) {
std::cout << "Calling base class." << std::endl;
return_type returnValue;
for( typename RangeIterMap::const_iterator it = rangeIter.begin();
it != rangeIter.end(); ++it) {
returnValue.insert(
make_pair(it->first, *get<2>(it->second))
);
}
return returnValue;
}
virtual bool advanceRangeIter(RangeIterMap &rangeIter) {
for (typename RangeIterMap::iterator it = rangeIter.begin(); ; ) {
++(get<2>(it->second));
if (get<2>(it->second) == get<1>(it->second)) {
if (it + 1 == rangeIter.end()) {
return mode::stopIter;
} else {
// cascade
get<2>(it->second) = get<0>(it->second);
++it;
}
} else {
// normal break point
return mode::continueIter;
}
}
return mode::continueIter;
}
};
typedef boost::integer_range<int> _intRange;
typedef boost::container::flat_map<char, _intRange> CharRange;
typedef boost::container::flat_map<char, int> ResidueCount;
template <class Container2D,
class return_type = boost::container::flat_map<typename Container2D::value_type::first_type,
typename Container2D::value_type::second_type::value_type> >
struct BaseIterContainer {
typedef CartProductIterator2DMap<Container2D, return_type> const_iterator;
const Container2D &_container;
BaseIterContainer( const Container2D &container) : _container(container) {}
const_iterator begin() const { return const_iterator(_container); }
const_iterator end() const { return const_iterator(); }
};
typedef BaseIterContainer<CharRange, ResidueCount> BaseCharRangeIter;
typedef CartProductIterator2DMap<CharRange, ResidueCount> BaseCPIterator;
class DerivedCPIterator : public BaseCPIterator {
public:
DerivedCPIterator() : BaseCPIterator() {}
DerivedCPIterator(const CharRange & charRange) : BaseCPIterator(charRange) {}
protected:
ResidueCount genReturnValue(const RangeIterMap &rangeIter) {
std::cout << "Calling derived class." << std::endl;
ResidueCount returnValue;
for( RangeIterMap::const_iterator it = rangeIter.begin();
it != rangeIter.end(); ++it) {
const char aa = it->first;
const int aaCount = *get<2>(it->second);
if (aaCount > 0) {
returnValue.insert(
make_pair(aa, aaCount)
);
}
}
return returnValue;
}
};
struct DerivedCharRangeIter {
typedef DerivedCPIterator const_iterator;
const CharRange &_container;
DerivedCharRangeIter( const CharRange &container) : _container(container) {}
const_iterator begin() const { return const_iterator(_container); }
const_iterator end() const { return const_iterator(); }
};
std::ostream& operator<<(std::ostream& out, const ResidueCount &rCount) {
foreach(const ResidueCount::value_type& aaCount, rCount) {
char aa = aaCount.first;
int totalAACount = aaCount.second;
out << "(" << aa << "," << totalAACount << ")";
}
return out;
}
int main(int argc, char **argv) {
cout << "Base Container" << endl;
CharRange test;
test.insert(make_pair('a', _intRange(0, 3)));
test.insert(make_pair('b', _intRange(0, 3)));
BaseCharRangeIter t(test);
BaseCharRangeIter::const_iterator it = t.begin();
for( ;it != t.end(); ++it) {
cout << *it << endl;
}
cout << endl;
cout << "Derived Container: " << endl;
DerivedCharRangeIter r(test);
DerivedCharRangeIter::const_iterator rt = r.begin();
for( ; rt != r.end(); ++rt) {
cout << *rt << endl;
}
return 0;
}
そして私が得る結果:
Base Container
Calling base class.
(a,0)(b,0)
Calling base class.
(a,1)(b,0)
Calling base class.
(a,2)(b,0)
Calling base class.
(a,0)(b,1)
Calling base class.
(a,1)(b,1)
Calling base class.
(a,2)(b,1)
Calling base class.
(a,0)(b,2)
Calling base class.
(a,1)(b,2)
Calling base class.
(a,2)(b,2)
Derived Container:
Calling base class.
(a,0)(b,0)
Calling derived class.
(a,1)
Calling derived class.
(a,2)
Calling derived class.
(b,1)
Calling derived class.
(a,1)(b,1)
Calling derived class.
(a,2)(b,1)
Calling derived class.
(b,2)
Calling derived class.
(a,1)(b,2)
Calling derived class.
(a,2)(b,2)
各genReturnValueは、呼び出しごとにそのクラス(ベースまたは派生)を出力します。基本クラスは正常に機能します。ただし、派生クラスはそうではありません。最初の反復では基本クラスgenReturnValueが呼び出され、0は除外されません。ただし、それ以上の反復は行います。
これはテンプレートと派生クラスへの私の最初の進出であるため、明らかな何かが欠けていると確信していますが、私の人生ではそれを理解することはできません。GCC4.6.3とClang3.0-6は同じ出力を提供します。
やめろ!
編集:また、私はC++プログラミングに比較的慣れていません。批評、スタイル、その他の批評があれば、私はそれを受け入れます。ありがとう!