C++ `std::enable_if` | Conditional Templates and SFINAE

C++ `std::enable_if` | Conditional Templates and SFINAE

이 글의 핵심

`std::enable_if` removes overload candidates when a condition is false—core SFINAE machinery before concepts.

What is enable_if?

Conditionally enable template declarations when a predicate is true.

#include <type_traits>

template<typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
func(T value) {
    return value * 2;
}

func(10);     // OK: int
// func(3.14);  // error: double

Basic syntax

// enable_if<condition, type>::type
std::enable_if<true, int>::type   // int
std::enable_if<false, int>::type // no ::type (SFINAE)

// C++14 alias
std::enable_if_t<condition, type>

Examples

Return type

template<typename T>
std::enable_if_t<std::is_integral<T>::value, T>
multiply(T a, T b) {
    return a * b;
}

template<typename T>
std::enable_if_t<std::is_floating_point<T>::value, T>
multiply(T a, T b) {
    return a * b * 1.1;
}

Default template parameter

template<typename T, 
         typename = std::enable_if_t<std::is_arithmetic<T>::value>>
class Calculator {
    T value;
public:
    Calculator(T v) : value(v) {}
    T add(T x) { return value + x; }
};

Dummy function parameter

template<typename T>
void print(T value, 
           std::enable_if_t<std::is_pointer<T>::value>* = nullptr) {
    std::cout << "pointer: " << *value << std::endl;
}

template<typename T>
void print(T value,
           std::enable_if_t<!std::is_pointer<T>::value>* = nullptr) {
    std::cout << "value: " << value << std::endl;
}

Multiple conditions

template<typename T>
std::enable_if_t<
    std::is_integral<T>::value && 
    !std::is_same<T, bool>::value,
    T>
increment(T value) {
    return value + 1;
}

C++20 concepts alternative

template<typename T>
concept Integral = std::is_integral_v<T>;

template<Integral T>
T multiply(T a, T b) {
    return a * b;
}

Common pitfalls

  • Readability—prefer enable_if_t and concepts.
  • Overlapping predicates—make conditions mutually exclusive.
  • Error messages—add static_assert in a single overload if clearer.

Practical patterns

Pointers only, copy-constructible checks, sizeof bounds—same ideas as the Korean article.

FAQ

SFINAE: Substitution Failure Is Not An Error—failed substitution removes a candidate, it is not always an error.


  • SFINAE
  • Type traits
  • SFINAE & Concepts

Keywords

C++, enable_if, SFINAE, templates, metaprogramming.

See also

  • SFINAE
  • SFINAE deep dive series
  • Tag dispatch
  • Type traits