我正在研究一组 n 维笛卡尔产品类,松散地基于这个解决方案。
对于相同的基本算法集,我有许多不同的数据类型,我想“啊哈!我将使用模板来减少我的整体工作!” 而且,直到现在,它的工作都很棒。我正在使用 Boost 的 iterator_facade。
我的问题是我使用的派生类map<char, boost::integer_range<int> >
。每次迭代都会产生 a map<char,int>
,但我排除了第二个值为 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。然而,进一步的迭代确实如此。
由于这是我第一次涉足模板和派生类,我确信我遗漏了一些明显的东西,但对于我的生活,我无法弄清楚。GCC 4.6.3 和 Clang 3.0-6 提供相同的输出。
哈!
编辑:另外,我在 C++ 编程方面相对较新。我愿意接受批评,风格或其他,如果你有的话。谢谢!