for文とif文を投げ捨ててRangeの力でプログラミングしてみた

[for文とif文を使わないでプログラミングしてみた](https://qiita.com/SAKIchan/items/1ba150fbdf4e64ade548)

という記事が最近出てました。[Sprout](https://github.com/bolero-MURAKAMI/Sprout)使えよ、とかそういう思いはありつつ、Rangeの力で書いたらどうなるかなと思いました。

# 元のコード

```cpp
#include <ioistream>
int main()
{
    int radix; //基数
    int index; //指数
    //基数、指数の入力
    std::cin >> radix >> index;
    //答えを格納する変数
    int ans = 1;
    for (int i = 0; i < index; ++i)
    {
        ans *= radix;
    }
    //答えの出力
    std::cout << ans << std::endl;
    return 0;
}
```

# range-v3

RangeといえばC++20の・・・はとりあえずおいておいて、[range-v3](https://github.com/ericniebler/range-v3)の力を借りて行きましょう。

```cpp
#include <iostream>
#include <range/v3/all.hpp>

int main()
{
    std::uint32_t radix; //基数
    std::uint16_t index; //指数
    //基数、指数の入力
    std::cin >> radix >> index;
    const auto re = ranges::accumulate(ranges::view::ints(std::uint16_t{},index), 1, [radix](auto re, auto) { return re * radix; });
    std::cout << re << std::endl;
}
```

https://wandbox.org/permlink/Lt4N9uHSC9o0Ndm4

やっぱり合計したりする系はaccumulateにやらせたいですよね。スッキリしました。

ちなみにWandboxではrange-v3が使えますって話は
[君はまだWandboxの真の実力を知らない～C++er目線で～](https://qiita.com/yumetodo/items/ef24708900b0535aa28c)
でしましたね。

# range-v3を使えない状況下でもRangeの力を借りたい

まあつまり自分でRangeを作るわけで、つまりiteratorを作ることになります。こんなときは
[イテレータの解説をするなんて今更佳代](https://qiita.com/yumetodo/items/245e94a0e85db9bf5cbb)
の出番ですね！

で結果がこちら

```cpp
#include <iostream>
#include <numeric>
#include <type_traits>
#include <cstdint>
#include <cassert>
#include <limits>
template<typename Range, typename T, typename BinaryOperation>
T accumulate(Range&& r, T init, BinaryOperation&& op)
{
    return std::accumulate(std::begin(r), std::end(r), init, std::forward<BinaryOperation>(op));
}
template<typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>
class integer_range_iterator {
    T begin_;
    T end_;
    T n_;
public:
    using iterator_category = std::random_access_iterator_tag;
    using value_type = T;
    using difference_type = T;
    using pointer = T*;
    using reference = T&;
    constexpr integer_range_iterator(T begin, T end, T n) noexcept : begin_(begin), end_(end), n_(n) {}
    constexpr integer_range_iterator next() const noexcept
    {
        assert(this->n_ < this->end_);
        return { this->begin_, this->end_, this->n_ + 1};
    }
    constexpr integer_range_iterator prev() const noexcept
    {
        assert(this->begin_ < this->n_);
        return { this->begin_, this->end_, this->n_ - 1};
    }
    constexpr value_type operator*() const noexcept { return this->begin_ + this->n_; }
    // constexpr pointer operator->() const noexcept;
    constexpr integer_range_iterator& operator++() noexcept
    {
        assert(this->n_ < this->end_);
        ++this->n_;
        return *this;
    }
    constexpr integer_range_iterator operator++(int) noexcept
    {
        assert(this->n_ < this->end_);
        const auto re = *this;
        ++this->n_;
        return re;
    }
    constexpr integer_range_iterator& operator--() noexcept
    {
        assert(this->begin_ < this->n_);
        --this->n;
        return *this;
    }
    constexpr integer_range_iterator operator--(int) noexcept
    {
        assert(this->begin_ < this->n_);
        const auto re = *this;
        --this->n;
        return re;
    }
    constexpr integer_range_iterator operator+(difference_type n) const noexcept
    {
        assert(this->begin_ < this->n_ + n && this->n_ + n < this->end_);
        return { this->begin_, this->end_, this->n_ + n};
    }
    constexpr integer_range_iterator operator-(difference_type n) const noexcept
    {
        assert(this->begin_ < this->n_ - n && this->n_ - n < this->end_);
        return { this->begin_, this->end_, this->n_ - n};
    }
    constexpr integer_range_iterator& operator+=(difference_type n) noexcept
    {
        assert(this->begin_ < this->n_ + n && this->n_ + n < this->end_);
        this->n += n;
        return *this;
    }
    constexpr integer_range_iterator& operator-=(difference_type n) noexcept
    {
        assert(this->begin_ < this->n_ - n && this->n_ - n < this->end_);
        this->n -= n;
        return *this;
    }
    constexpr value_type operator[](difference_type n) const noexcept
    {
        assert(this->begin_ < this->n_ + n && this->n_ + n < this->end_);
        return this->begin_ + this->n_ + n;
    }
};
template<typename T1, typename T2>
inline constexpr bool operator==(const integer_range_iterator<T1>& l, const integer_range_iterator<T2>& r) noexcept
{
    return *l == *r;
}
template<typename T1, typename T2>
inline constexpr bool operator!=(const integer_range_iterator<T1>& l, const integer_range_iterator<T2>& r) noexcept
{
    return !(l == r);
}
template<typename T1, typename T2>
inline constexpr bool operator<(const integer_range_iterator<T1>& l, const integer_range_iterator<T2>& r) noexcept
{
    return *l < *r;
}
template<typename T1, typename T2>
inline constexpr bool operator>(const integer_range_iterator<T1>& l, const integer_range_iterator<T2>& r) noexcept
{
    return r < l;
}
template<typename T1, typename T2>
inline constexpr bool operator<=(const integer_range_iterator<T1>& l, const integer_range_iterator<T2>& r) noexcept
{
    return !(r < l);
}
template<typename T1, typename T2>
inline constexpr bool operator>=(const integer_range_iterator<T1>& l, const integer_range_iterator<T2>& r) noexcept
{
    return !(l < r);
}
template<typename T1, typename T2>
inline constexpr auto operator-(const integer_range_iterator<T1>& l, const integer_range_iterator<T2>& r) noexcept -> decltype(l.ptr() - r.ptr())
{
    return l.ptr() - r.ptr();
}
template<typename T>
inline constexpr integer_range_iterator<T> operator+(typename integer_range_iterator<T>::difference_type n, const integer_range_iterator<T>& it) noexcept
{
    return it + n;
}

template<typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>
class integer_range {
public:
    using iterator = integer_range_iterator<T>;
private:
    T begin_;
    T end_;
public:
    constexpr integer_range(T begin, T end) : begin_(begin), end_(end) {};
    iterator begin() const { return { this->begin_, this->end_, this->begin_}; }
    iterator end() const { return { this->begin_, this->end_, this->end_}; }
};
static_assert(std::is_trivially_copyable_v<integer_range<int>>);
int main()
{
    std::uint32_t radix; //基数
    std::uint16_t index; //指数
    //基数、指数の入力
    std::cin >> radix >> index;
    const auto ans = accumulate(integer_range<std::uint16_t>(0, index), std::uint64_t{1}, [radix](auto re, auto) { return re * radix; });
    //答えの出力
    std::cout << ans << std::endl;
    return 0;
}
```

https://wandbox.org/permlink/Y0bNLeDXbfvbWOvA

長い。C++でiterator作るの心が折れそう・・・。

# 結論

- せっかく`if`と`for`を排除したなら、意味論的なアルゴリズム関数に投げましょう
- Range-v3使おう