エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

C++でもFizzBuzz、ふたたび

ちょっとひっかかっていたことがあって。先日Haskellで書いたFizzBuzz。この考え方のままC++に持ってこられないものか。

で、書いてみました。Rangeクラスが無駄に大きくなってしまったのを除くと、意外に移し替えできた気分。

#include <iterator>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <boost/lexical_cast.hpp>

class Range
{
public:
    Range(int i, int j) : min_(std::min(i, j)), max_(std::max(i, j)) {}

    class iterator : public std::iterator<std::input_iterator_tag, int>
    {
    public:
        iterator() : i_(0) {}
        explicit iterator(int i) : i_(i) {}
        int& operator * ()          { return i_; }
        int operator * () const     { return i_; }
        iterator& operator ++ ()    { ++i_; return *this; }
        iterator  operator ++ (int) { iterator result(*this); ++i_; return result; }

    private:
        int i_;
    };

    iterator begin() const { return iterator(min_); }
    iterator end() const   { return iterator(max_); }

    int min() const { return min_; }
    int max() const { return max_; }

private:
    const int min_;
    const int max_;
};

bool operator == (const Range::iterator& lhs, const Range::iterator& rhs)
{
    return *lhs == *rhs;
}

bool operator != (const Range::iterator& lhs, const Range::iterator& rhs)
{
    return ! (lhs == rhs);
}

std::string fizzBuzz(int i)
{
    if     (i % 15 == 0) return "FizzBuzz";
    else if(i %  5 == 0) return "Buzz";
    else if(i %  3 == 0) return "Fizz";
    else                 return boost::lexical_cast<std::string>(i);
}

int main(int, char* [])
{
    // 1以上101未満の範囲の数値を、変換関数fizzBuzzを使って変換、結果は出力ストリームへ
    Range range(1, 101);
    std::transform(range.begin(), range.end(), std::ostream_iterator<std::string>(std::cout, "\n"), fizzBuzz);

    return 0;
}

追記

一晩たってから、イテレータがあれば充分ということに気がついた。

std::transform(Range::iterator(1), Range::iterator(101), 
            std::ostream_iterator<std::string>(std::cout, "\n"), fizzBuzz);

Rangeが大小関係を保証してますが、それをプログラマが管理するならイテレータを直接使ってもいいわけですね。