add tag
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)

This room is for discussion about this question.

Once logged in you can direct comments to any contributor here.

Enter question or answer id or url (and optionally further answer ids/urls from the same question) from

Separate each id/url with a space. No need to list your own answers; they will be imported automatically.