Jonathan Mee
I want to use [`std::underlying_type`](https://en.cppreference.com/w/cpp/types/underlying_type) with [`std::enable_if`](https://en.cppreference.com/w/cpp/types/enable_if) to conditionally cause [Substitution Failure Is Not An Error (SFINAE)](https://en.cppreference.com/w/cpp/language/sfinae). I'm using this function to conditionally allow either `unsigned int` parameters or enum parameters whose underlying type is `uint8_t`:
template <typename T>
std::enable_if_t<(std::is_enum_v<T> && std::is_same_v<std::underlying_type_t<T>, uint8_t>) || std::is_same_v<T, unsigned int>> Foo(const T param) {
std::cout << static_cast<int>(param) << std::endl;
}
However I'm getting the error when calling `Foo(13U)`:
> error: no matching function for call to `Foo(unsigned int)`
How can I change the `std::enable_if_t` parameter to make this work as intended?
[**Live Example**](http://coliru.stacked-crooked.com/a/ef210af489da6d12)
Top Answer
Jonathan Mee
The problem here is the [`std::underlying_type`](https://en.cppreference.com/w/cpp/types/underlying_type) struct template parameter must be an enumeration type:
> Otherwise, if `T` is not an enumeration type, there is no member `type`
This means calling `std::underlying_type_t<int>` is a compilation error. Short circuiting logical-and operators does not prevent template evaluation. To avoid this we'll need 2 things:
1. [`std::conditional`](https://en.cppreference.com/w/cpp/types/conditional) to optionally use `underlying_type`
1. And an alternative structure which has a `type` member which could be returned instead, I've chosen `template<typename... Ts> struct make_void { typedef void type; }` from https://en.cppreference.com/w/cpp/types/void_t
Using these 2 `Foo` can be written so that the `type` member of `std::underlying_type` is only accessed if `std::is_enum` is valid:
template <typename T>
std::enable_if_t<std::is_same_v<typename std::conditional_t<std::is_enum_v<T>, std::underlying_type<T>, decltype(make_void<T>())>::type, uint8_t> || std::is_same_v<T, unsigned int>> Foo(const T param) {
std::cout << static_cast<int>(param) << std::endl;
}
[**Live Example**](http://coliru.stacked-crooked.com/a/88f31ccbf8914208)