5.2.17 · D3C++ Programming

Worked examples — SFINAE — substitution failure is not an error

2,577 words12 min readBack to topic

Before any example, one reminder in plain words. A template is a recipe with a blank T in it. Substitution = the compiler pastes a real type into that blank. The signature is the "header" of a function — its return type and parameter types, the part written before the { }. The body is the { ... } part. SFINAE only watches the header.


The scenario matrix

Every situation SFINAE can face falls into one of these cells:

# Cell class What is fed in Expected outcome
1 Valid substitution type that does fit the signature candidate stays, compiles
2 Failure in signature type missing a member named in the header candidate silently dropped (SFINAE)
3 Failure in body header fine, { } uses a missing member hard error — NOT SFINAE
4 enable_if = true condition holds → ::type exists overload enabled
5 enable_if = false condition fails → no ::type overload disabled (SFINAE)
6 Overlapping conditions two overloads both valid ambiguous hard error
7 Degenerate / empty input .size() on an empty container valid — returns 0, no SFINAE involved
8 Limiting: last candidate removed no viable overload survives "no matching function" error
9 Word problem real logging function choosing paths correct path picked at compile time
10 Exam twist enable_if in return type of identical templates "redefinition" trap

The examples below hit every cell. The label [Cell N] tells you which.


Example 1 — Valid substitution [Cell 1]


Example 2 — Failure in the signature [Cell 2]

See Templates and Type Deduction for why deduction happens before substitution.


Example 3 — Failure in the body (NOT SFINAE) [Cell 3]

Figure — SFINAE — substitution failure is not an error

Example 4 — enable_if = true [Cell 4]


Example 5 — enable_if = false [Cell 5]


Example 6 — Overlapping conditions = ambiguity [Cell 6]


Example 7 — Degenerate / empty input [Cell 7]


Example 8 — Limiting case: last candidate removed [Cell 8]


Example 9 — Word problem: a smart logger [Cell 9]


Example 10 — Exam twist: the "redefinition" trap [Cell 10]


Recall Which cells produce which compiler behaviour?

Silent drop happens in cells 2, 5, 8 (signature failure). Hard error in 3 (body), 6 (ambiguous), 10-naive (redefinition). Cells 1, 4, 7, 9 all compile and run. Match message to mechanism: "no matching function" = SFINAE removed candidates; "no member named X" = body error; "ambiguous" = overlapping conditions.


Connections

  • SFINAE — substitution failure is not an error (index 5.2.17) — parent
  • Templates and Type Deduction
  • std::enable_if and Tag Dispatch
  • decltype and Trailing Return Types
  • Type Traits (std::is_integral, std::void_t)
  • void_t Detection Idiom
  • Overload Resolution
  • Concepts (C++20)