# enable_if

suggest change`std::enable_if`

is a convenient utility to use boolean conditions to trigger SFINAE. It is defined as:

```
template <bool Cond, typename Result=void>
struct enable_if { };
template <typename Result>
struct enable_if<true, Result> {
using type = Result;
};
```

That is, `enable_if<true, R>::type`

is an alias for `R`

, whereas `enable_if<false, T>::type`

is ill-formed as that specialization of `enable_if`

does not have a `type`

member type.

`std::enable_if`

can be used to constrain templates:

```
int negate(int i) { return -i; }
template <class F>
auto negate(F f) { return -f(); }
```

Here, a call to `negate(1)`

would fail due to ambiguity. But the second overload is not intended to be used for integral types, so we can add:

```
int negate(int i) { return -i; }
template <class F, class = typename std::enable_if<!std::is_arithmetic<F>::value>::type>
auto negate(F f) { return -f(); }
```

Now, instantiating `negate<int>`

would result in a substitution failure since `!std::is_arithmetic<int>::value`

is `false`

. Due to SFINAE, this is not a hard error, this candidate is simply removed from the overload set. As a result, `negate(1)`

only has one single viable candidate - which is then called.

# When to use it

It’s worth keeping in mind that `std::enable_if`

is a helper *on top* of SFINAE, but it’s not what makes SFINAE work in the first place. Let’s consider these two alternatives for implementing functionality similar to `std::size`

, i.e. an overload set `size(arg)`

that produces the size of a container or array:

```
// for containers
template<typename Cont>
auto size1(Cont const& cont) -> decltype( cont.size() );
// for arrays
template<typename Elt, std::size_t Size>
std::size_t size1(Elt const(&arr)[Size]);
// implementation omitted
template<typename Cont>
struct is_sizeable;
// for containers
template<typename Cont, std::enable_if_t<std::is_sizeable<Cont>::value, int> = 0>
auto size2(Cont const& cont);
// for arrays
template<typename Elt, std::size_t Size>
std::size_t size2(Elt const(&arr)[Size]);
```

Assuming that `is_sizeable`

is written appropriately, these two declarations should be exactly equivalent with respect to SFINAE. Which is the easiest to write, and which is the easiest to review and understand at a glance?

Now let’s consider how we might want to implement arithmetic helpers that avoid signed integer overflow in favour of wrap around or modular behaviour. Which is to say that e.g. `incr(i, 3)`

would be the same as `i += 3`

save for the fact that the result would always be defined even if `i`

is an `int`

with value `INT_MAX`

. These are two possible alternatives:

```
// handle signed types
template<typename Int>
auto incr1(Int& target, Int amount)
-> std::void_t<int[static_cast<Int>(-1) < static_cast<Int>(0)]>;
// handle unsigned types by just doing target += amount
// since unsigned arithmetic already behaves as intended
template<typename Int>
auto incr1(Int& target, Int amount)
-> std::void_t<int[static_cast<Int>(0) < static_cast<Int>(-1)]>;
template<typename Int, std::enable_if_t<std::is_signed<Int>::value, int> = 0>
void incr2(Int& target, Int amount);
template<typename Int, std::enable_if_t<std::is_unsigned<Int>::value, int> = 0>
void incr2(Int& target, Int amount);
```

Once again which is the easiest to write, and which is the easiest to review and understand at a glance?

A strength of `std::enable_if`

is how it plays with refactoring and API design. If `is_sizeable<Cont>::value`

is meant to reflect whether `cont.size()`

is valid then just using the expression as it appears for `size1`

can be more concise, although that could depend on whether `is_sizeable`

would be used in several places or not. Contrast that with `std::is_signed`

which reflects its intention much more clearly than when its implementation leaks into the declaration of `incr1`

.