This code works in VS2013 and other compilers (tested clang 3.4 and gcc 4.8) but fails to compile in VS2012:
#include <type_traits>
#include <cstdio>
// error C4519: default template arguments are only allowed on a class template
template<typename E, typename std::enable_if<std::is_enum<E>::value>::type* = nullptr>
typename std::underlying_type<E>::type to_integral(E e)
{
return static_cast<typename std::underlying_type<E>::type>(e);
}
template<typename E, typename std::enable_if<!std::is_enum<E>::value>::type* = nullptr>
E to_integral(E e)
{
return e;
}
enum class MyEnum : int { A = 5 };
int main()
{
auto a = to_integral(42);
auto b = to_integral(MyEnum::A);
printf("%d\n", a);
printf("%d\n", b);
}
How can I write to_integral
in VS2012? Is it possible? I tried using enable_if
on the return argument and as a parameter but then the underlying_type
appears in the function signature which compilers tend not to like for non-enum types.
Put the
enable_if
in the return type:or the simpler:
for the first specialization. For the second, I'd recommend:
should work in MSVC2012 live example. Note the extra condition, and the
std::move
(just in case you have a bigint class that qualifies as is_integral). (it is usually allowed to specialize such traits instd
). It also means that if you callto_integral(3.14)
you get an error, which I think is good.Oh, and
template<bool b, class T=void>using enable_if_t=typename std::enable_if<b,T>::type;
can save a lot oftypename
spam (however, 2012 either has lack of support, and 2013 has flaky support, for this kind of thing).