#include <iostream>
#include <stdexcept>
#include <type_traits>
#define noexcept
namespace
{
enum class Block_Edges : int
{
from = 0,
to = 4,
};
template<typename T, bool enable = std::is_enum<T>::value>
int operator+(const T& e, int i)
{
//const T rei = i + static_cast<int>(e);
const int rei = i + static_cast<int>(e);
if (rei < static_cast<int>(T::from) || rei > static_cast<int>(T::to))
{
throw std::out_of_range("Addition to Row_Edges would create out of bounds index");
}
return rei;
}
template<typename T, bool enable = std::is_enum<T>::value>
int operator-(const T& e, int i)
{
const int rei = i - static_cast<int>(e);
if (rei < static_cast<int>(T::from) || rei > static_cast<int>(T::to))
{
throw std::out_of_range("Addition to Row_Edges would create out of bounds index");
}
return rei;
}
template<typename T, bool enable = std::is_enum<T>::value>
int& operator++(T& e)
{
return e = static_cast<int>(e + 1);
}
#if 0 //this does not do the right thing
template<typename T, bool enable = std::is_enum<T>::value>
const int& operator*(T& e)
{
return static_cast<int>(e);
}
#endif
};
template<typename T, bool enable = std::is_integral<T>::value || std::is_enum<T>::value>
struct range_impl
{
struct iterator
{
const T operator * ()const noexcept
{
return value;
}
iterator& operator ++() noexcept
{
++value;
return *this;
}
friend const bool operator != (const iterator& lhs, const iterator& rhs) noexcept
{
return lhs.value != rhs.value;
}
T value;
};
std::size_t size() const
{
return last - first;
}
const iterator begin()const noexcept
{
return{ first };
}
const iterator end()const noexcept
{
return{ last };
}
T first;
T last;
};
template<typename T>
struct range_impl<T, false>
{
range_impl(T first, T last)
: first(first)
, last(last)
{}
std::size_t size() const
{
return std::distance(first, last);
}
const T begin()const noexcept
{
return{ first };
}
const T end()const noexcept
{
return{ last };
}
T first;
T last;
};
//template<typename T>
//range_impl<T> range(T first, T last) noexcept
//{
// return{ first, last };
//}
template<typename T1, typename T2>
range_impl<typename std::common_type<T1, T2>::type>
range(T1 first, T2 last) noexcept
{
return{ first, last };
}
int main()
{
for (const auto& i : range(Block_Edges::from - 1, Block_Edges::to + 1)) //succeeds
{
std::cout << '\n' << i << ':';
for (const auto& j : range(Block_Edges::from - 2, Block_Edges::to + 0))
{
std::cout << j << ' ';
}
}
}