0Pricing
C++ Academy · Lesson

enable_if Patterns

Constrain templates the classic way.

enable_if Patterns is a free C++ Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C++ Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Is enable_if?

std::enable_if is a small trait that conditionally defines a type member. When its condition is true the type exists; when false, the surrounding template is removed via SFINAE.

  • Lives in <type_traits>.
  • It is the classic tool for constraining templates.
#include <iostream>
#include <type_traits>

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

int main() {
    std::cout << doubleIt(21) << '\n';
    return 0;
}

How It Works

enable_if<Cond, T>::type is T only when Cond is true. If false, there is no type member, so the substitution fails.

#include <iostream>
#include <type_traits>

int main() {
    std::cout << std::boolalpha;
    std::cout << std::is_same<std::enable_if<true, int>::type, int>::value << '\n';
    return 0;
}

enable_if in the Return Type

The most common placement is the return type. The function only exists when the condition holds.

#include <iostream>
#include <type_traits>

template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
half(T v) { return v / 2; }

int main() {
    std::cout << half(5.0) << '\n';
    return 0;
}

enable_if as a Template Parameter

Another idiom puts enable_if in a defaulted template parameter, keeping the return type clean.

#include <iostream>
#include <type_traits>

template <typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
T triple(T v) { return v * 3; }

int main() {
    std::cout << triple(4) << '\n';
    return 0;
}

enable_if_t Shortcut

C++14 added the alias std::enable_if_t<Cond, T> so you can skip the typename ...::type noise.

#include <iostream>
#include <type_traits>

template <typename T>
std::enable_if_t<std::is_integral<T>::value, T>
negate(T v) { return -v; }

int main() {
    std::cout << negate(8) << '\n';
    return 0;
}

Pairing Two Overloads

Provide complementary conditions so exactly one overload is valid for any type, with no ambiguity.

#include <iostream>
#include <type_traits>

template <typename T>
std::enable_if_t<std::is_integral<T>::value, const char*>
category() { return "integer"; }

template <typename T>
std::enable_if_t<!std::is_integral<T>::value, const char*>
category() { return "non-integer"; }

int main() {
    std::cout << category<int>() << ' ' << category<double>() << '\n';
    return 0;
}

Combining Conditions

Use logical operators on trait values to express richer constraints, like "integral and signed".

#include <iostream>
#include <type_traits>

template <typename T>
std::enable_if_t<std::is_integral<T>::value && std::is_signed<T>::value, T>
magnitude(T v) { return v < 0 ? -v : v; }

int main() {
    std::cout << magnitude(-12) << '\n';
    return 0;
}

Constraining a Constructor

You can place enable_if on a constructor's template parameter to allow it only for compatible types.

#include <iostream>
#include <type_traits>

struct Wrapper {
    int value;
    template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
    Wrapper(T v) : value(static_cast<int>(v)) {}
};

int main() {
    Wrapper w(42);
    std::cout << w.value << '\n';
    return 0;
}

Default Template Argument Pitfall

Two overloads that differ only by a defaulted enable_if template parameter are seen as redefinitions. Give them different forms (for example put one condition on the return type).

#include <iostream>
#include <type_traits>

template <typename T>
std::enable_if_t<std::is_integral<T>::value, void>
printKind() { std::cout << "int\n"; }

template <typename T>
std::enable_if_t<std::is_floating_point<T>::value, void>
printKind() { std::cout << "float\n"; }

int main() {
    printKind<int>();
    printKind<double>();
    return 0;
}

Comparison to Concepts

C++20 concepts replace most enable_if usage with far clearer syntax, but enable_if remains essential for pre-C++20 code and some edge cases.

#include <iostream>
#include <type_traits>

template <typename T>
std::enable_if_t<std::is_arithmetic<T>::value, T>
square(T v) { return v * v; }

int main() {
    std::cout << square(6) << ' ' << square(1.5) << '\n';
    return 0;
}

A Complete Example

Combine everything: a function family that formats integers and floats differently, selected at compile time.

#include <iostream>
#include <type_traits>

template <typename T>
std::enable_if_t<std::is_integral<T>::value, void>
format(T v) { std::cout << "int[" << v << "]\n"; }

template <typename T>
std::enable_if_t<std::is_floating_point<T>::value, void>
format(T v) { std::cout << "float(" << v << ")\n"; }

int main() {
    format(10);
    format(3.5);
    return 0;
}

Quick Check

Test your understanding of enable_if.

Recap

You learned the classic enable_if patterns:

  • defines ::type only when the condition is true, enabling SFINAE
  • placed in the return type or a defaulted template parameter
  • use the enable_if_t alias and combine traits with logical operators
  • concepts supersede it in C++20, but it remains widely used

That completes the Template Specialization and SFINAE course.

Frequently asked questions

Is the “enable_if Patterns” lesson free?

Yes — the full text of “enable_if Patterns” is free to read here on the web, and the C++ Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C++ Academy course, upgrade to CoddyKit PRO.

What will I learn in “enable_if Patterns”?

Constrain templates the classic way. You practise C++ Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start C++ Academy?

No prior experience is required. C++ Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “enable_if Patterns” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this C++ Academy lesson?

Yes. Every C++ Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Full Specialization
  2. Partial Specialization
  3. SFINAE
  4. enable_if Patterns
← Back to C++ Academy