Ch7.3: if constexpr
Overview
if constexpr is a compile‑time conditional. When its condition
is a constant expression, the compiler removes the branch that is not taken.
This is different from a normal if, which always generates both
branches in the program.
This chapter shows how if constexpr works, how to chain
else if constexpr, how it can replace certain uses of
#ifdef, and how it helps prevent hidden syntax errors.
1. Basic example
If the condition is a constant expression, the compiler keeps only the selected branch.
constexpr bool use_fast_path = true;
int compute(int x)
{
if constexpr(use_fast_path)
{
return x * 2; // this branch is kept
}
else
{
return x + 2; // this branch is removed
}
}
Because use_fast_path is constexpr, the compiler
discards the else branch entirely.
2. Why this matters
if constexpr is useful when you want to:
- select code paths at compile time
- remove unused code entirely
- avoid generating code that would be invalid in some cases
Unlike a normal if, the discarded branch is not compiled at
all.
3. if constexpr / else if constexpr / else
You can chain if constexpr with else if constexpr
and else. Only one branch is selected, and all others are
removed at compile time.
#include <fast_io.h>
constexpr int mode = 2;
void handle_mode()
{
using namespace ::fast_io::iomnp;
if constexpr(mode == 1)
{
print("mode 1\n");
}
else if constexpr(mode == 2)
{
print("mode 2\n");
}
else
{
print("other mode\n");
}
}
Only the matching branch is kept in the final program.
4. Using it with constexpr variables
A common pattern is to control behavior using a constexpr
configuration variable.
#include <fast_io.h>
constexpr bool print_hex = false;
void print_value(int x)
{
using namespace ::fast_io::iomnp;
if constexpr(print_hex)
print("hex: ", hex(x), "\n");
else
print("dec: ", x, "\n");
}
If print_hex is false, the compiler removes the
entire hex printing branch.
5. Replacing some #ifdef usage
if constexpr is very useful when combined with macros. In many
cases, it can replace #ifdef inside functions. The idea is to
convert a macro into a constexpr boolean, and then use
if constexpr to remove unused branches at compile time.
#include <fast_io.h>
void foo()
{
using namespace ::fast_io::iomnp;
constexpr bool is_windows{
#ifdef _WIN32
true
#else
false
#endif
};
if constexpr(is_windows)
{
win32_foo();
}
else
{
posix_foo();
}
}
This keeps the function readable and avoids scattering #ifdef
throughout the code.
6. Why this is safer than large #ifdef blocks
#ifdef removes code before the compiler ever sees it. This can
hide syntax errors or invalid code inside the disabled branch.
For example:
#ifdef _WIN32
win32_foo();
#else
foo() // missing semicolon, but never compiled on Windows
#endif
On Windows, the foo() line is removed by the preprocessor, so
the compiler never checks it. The error remains hidden until someone builds
on a different platform.
With if constexpr, both branches must be valid C++. The
compiler parses both, then discards the unused one only after verifying it.
#include <fast_io.h>
void foo()
{
using namespace ::fast_io::iomnp;
constexpr bool is_windows{
#ifdef _WIN32
true
#else
false
#endif
};
if constexpr(is_windows)
win32_foo();
else
foo(); // must be valid C++ or compilation fails
}
This reduces the chance of hidden compilation failures.
7. Using if constexpr(false) to disable code
if constexpr(false) can be used to temporarily disable a block
of code. The disabled branch is removed at compile time, but the compiler
still checks it for correctness.
if constexpr(false)
{
do_something(); // must still be valid C++
}
This is different from:
#if 0
do_something() // missing semicolon, but never checked
#endif
#if 0 is still useful when the programmer intentionally wants
to hide unfinished or syntactically invalid code. In that case, the goal is
to prevent the compiler from seeing the code at all.
But when you want the compiler to keep checking the disabled code for
correctness, if constexpr(false) is the safer choice.
8. Checking endianness with if constexpr
if constexpr is also useful for selecting code paths based on
compile‑time properties of the platform, such as endianness.
#include <bit>
#include <fast_io.h>
void show_endianness()
{
using namespace ::fast_io::iomnp;
if constexpr(::std::endian::little == ::std::endian::native)
{
print("native endianness: little\n");
}
else if constexpr(::std::endian::big == ::std::endian::native)
{
print("native endianness: big\n");
}
else
{
print("native endianness: mixed or unknown\n");
}
}
Only the matching branch is kept in the final program.
Key takeaways
if constexpris a compile‑time conditional.- You can chain it with
else if constexprandelse. - Unused branches are removed when the condition is a constant expression.
- It can replace some
#ifdefusage inside functions. - It prevents hidden syntax errors in disabled branches.
if constexpr(false)disables code but still checks it.#if 0is still useful when intentionally hiding invalid code.- It can select platform‑specific code paths, such as endianness.