#include <stdexcept>
#include <iostream>

template <typename T>
struct fibonacci_sequence
{
    using value_type = T;

    value_type operator()()
    {
        if (next < current)
            throw std::overflow_error("Overflow encountered in fibonacci_sequence.");

        auto result = current;

        auto next_in_series = current + next;
        current = next;
        next = next_in_series;

        return result;
    }


private:
    value_type current = 0;
    value_type next = 1;
};

template <typename sequence>
void largest_generated(sequence& seq)
{
    typename sequence::value_type largest = 0;

    try {
        for (;;)
            largest = seq();
    }

    catch (std::exception& ex)
    {
        std::cout << ex.what() << '\n';
        std::cout << "Last value generated was " << largest << "\n\n";
    }
}

int main()
{
    fibonacci_sequence<int> int_seq;
    fibonacci_sequence<unsigned> unsigned_seq;
    fibonacci_sequence<unsigned long long> ull_seq;

    largest_generated(int_seq);
    largest_generated(unsigned_seq);
    largest_generated(ull_seq);
}