Is too late to play?
I propose a slightly different solution that uses tag dispatching and components already defined in the standard (std::true_type and std::false_type) that simplify the development.
Instead your class EnumConstantDefined_totalNum you can simply declare a couple of template function and a template constexpr variable as follows
template <typename Enum>
auto checkEnumFunc (int) -> decltype( Enum::totalNum, std::true_type{});
template <typename>
auto checkEnumFunc (long) -> std::false_type;
template <typename Enum>
static constexpr auto checkEnum = decltype(checkEnumFunc<Enum>(0))::value;
The assertValueIsInRange() template functions become
template <class EnumType>
std::enable_if_t<checkEnum<EnumType>, void> assertValueIsInRange (std::underlying_type_t<EnumType> value)
{
assert (value < static_cast<decltype(value)>(EnumType::totalNum));
}
template <class EnumType>
std::enable_if_t<not checkEnum<EnumType>, void> assertValueIsInRange (std::underlying_type_t<EnumType> value)
{
// do nothing
}
The following is a full compiling C++14 example
#include <cassert>
#include <cstdint>
#include <type_traits>
enum class Foo : int
{
a,
b,
c,
totalNum
};
enum class Bar : bool
{
oneOption,
otherOption
};
template <typename Enum>
auto checkEnumFunc (int) -> decltype( Enum::totalNum, std::true_type{});
template <typename>
auto checkEnumFunc (long) -> std::false_type;
template <typename Enum>
static constexpr auto checkEnum = decltype(checkEnumFunc<Enum>(0))::value;
template <class EnumType>
std::enable_if_t<checkEnum<EnumType>, void> assertValueIsInRange (std::underlying_type_t<EnumType> value)
{
assert (value < static_cast<decltype(value)>(EnumType::totalNum));
}
template <class EnumType>
std::enable_if_t<not checkEnum<EnumType>, void> assertValueIsInRange (std::underlying_type_t<EnumType> value)
{
// do nothing
}
template <class EnumClassType>
EnumClassType typeToEnum (typename std::underlying_type<EnumClassType>::type value)
{
assertValueIsInRange<EnumClassType> (value);
return EnumClassType (value);
}
int main ()
{
typeToEnum<Foo>(0); // doesn't fails
// typeToEnum<Foo>(10); // fails!
typeToEnum<Bar>(0); // doesn't fails
typeToEnum<Bar>(10); // doesn't fails
}
enumand has::totalNumit then does the static assert.