我正在开发一组 n 维笛卡尔积类,基于此 解决方案。我有许多不同的数据类型适用于相同的基本算法,所以我想:“啊哈!我将使用模板来减少我的工作量!”直到现在,这个想法一直很好。我正在使用 Boost 的 iterator_facade。
我的问题是,我制作了一个派生类来处理
这个派生类重载了生成迭代器返回值的函数,并且它起作用了。然而,在第一次迭代期间,基类的生成器被调用了。我非常困惑。有人有什么想法吗?
以下是相关的代码片段:
每个genReturnValue在每次调用时都会打印其类(基类或派生类)。基类函数按照预期工作。然而,派生类没有。第一次迭代调用了基类的genReturnValue,并且0没有被过滤掉。但是,进一步的迭代则可以。
由于这是我第一次尝试使用模板和派生类,我肯定错过了一些显而易见的东西,但是我无法弄清楚。GCC 4.6.3和Clang 3.0-6提供相同的输出。
帮忙!
另外,我相对新于C++编程。如果您有任何批评,风格或其他方面,我很乐意接受。谢谢!
我的问题是,我制作了一个派生类来处理
map<char, boost::integer_range<int> >
。每次迭代都会生成一个 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++编程。如果您有任何批评,风格或其他方面,我很乐意接受。谢谢!