Digits
Problems like those at Project Euler often involve the digits of a number. The solution will usually require something cleverer than iterating over them, however doing so may be the avenue to understanding the problem. It is a shame then that there is no simple way to do so in C++; it is possible to convert the number to a string with std::to_string, but then it is necessary to convert the characters to integers for arithmetic operations, getting in the way of STL algorithms. Clearly(!), it is needed to write an iterator:
#include <boost/iterator/iterator_facade.hpp>
class DigitIterator :
public boost::iterator_facade<
DigitIterator, //CRTP
const int, //type iterated over
boost::forward_traversal_tag //kind of traversal
int //'reference'
>
{
public:
DigitIterator(int n = 0):
value(n)
{ }
private:
friend class boost::iterator_core_access;
void increment() {
value /= 10;
}
int dereference() const {
return value % 10;
}
bool equal(const DigitIterator &other) const {
return value == other.value;
}
int value;
};
- The iterator increments by dividing the value it holds by 10
- The current digit is simply the value modulo 10
- The ‘end’ iterator holds a value of 0
- Since it discards old values, it may be used only for forward traversal
- The type iterated over is set to const because the dereference operator returns a copy, not allowing modification of the number
- The ‘reference’ template argument is not an actual reference for the same reason
A range can then be made out of a pair of these:
#include <boost/range/iterator_range.hpp>
auto digits_of(int n)
{
return boost::make_iterator_range(DigitIterator(n), DigitIterator());
}
In C++14 it is not necessary to specify the function’s return type. Done! It is now possible to iterate over the digits with a range-based for, or STL/Boost algorithms:
int main(){
int n = 1537;
for (const auto digit : digits_of(n))
cout << digit << '\n';
cout << "Sum: " << accumulate(digits_of(n), 0) << '\n';
}
7
3
5
1
Sum: 16