Question

constexpr vs const in C++: What’s the Difference and When to Use Each

cppc++11constantsconstexpr

Question

What is the difference between constexpr and const in C++?

When can only one of them be used? When can both be used, and how should you decide which one to choose?

Short Answer

By the end of this page, you will understand that const means a value cannot be modified after initialization, while constexpr means a value or function can be evaluated at compile time when possible. You will learn when they overlap, when they differ, and how to choose the right one in practical C++ code.

Concept

const and constexpr are related, but they are not the same thing.

const

const means read-only after initialization. Once a const variable has been given a value, your program cannot change it.

const int x = 10;
// x = 20; // error

This does not automatically mean the value is known at compile time.

int n = getValue();
const int x = n; // valid if n is available at runtime

Here, x is still read-only, but its value depends on runtime data.

constexpr

constexpr means the value is intended to be a constant expression, which means the compiler can compute it at compile time.

constexpr int x = 10;

A constexpr variable must be initialized with a compile-time constant expression.

int n = 5;
constexpr int x = n; // error: n is not a constant expression

Key idea

  • const = cannot be changed
  • constexpr = known at compile time

A constexpr object is also effectively const, because if something is known at compile time and fixed, you cannot later modify it.

Why this matters

The distinction matters because some language features require values to be known at compile time, such as:

  • array sizes in some contexts
  • template arguments
  • case labels in switch
  • compile-time calculations
  • constant initialization for performance or correctness

So if you only need a read-only variable, const may be enough. If the compiler must know the value during compilation, you need constexpr.

Mental Model

Think of const and constexpr like labels on a box:

  • const means "this box is sealed after you fill it".
  • constexpr means "this box must be filled before the factory ships it".

With const, you can fill the box later at runtime, then seal it. With constexpr, the box must already be filled during compilation.

So:

  • const focuses on immutability
  • constexpr focuses on compile-time availability
Take Quiz

Syntax and Examples

Basic syntax

const int a = 10;
constexpr int b = 10;

Both are read-only, but b is also guaranteed to be a constant expression.

Example 1: const with a runtime value

#include <iostream>

int getAge() {
    return 25;
}

int main() {
    const int age = getAge();
    std::cout << age << '\n';
}

age cannot be changed after initialization, but it is not necessarily known at compile time because it comes from a function call that runs at runtime.

Example 2: constexpr with a compile-time value

constexpr int daysInWeek = 7;
constexpr int hoursInDay = 24;
constexpr int hoursInWeek = daysInWeek * hoursInDay;

The compiler can calculate hoursInWeek before the program runs.

Example 3: constexpr function

constexpr int square(int x) {
    return x * x;
}

constexpr int result = square(5);

Because square(5) can be evaluated at compile time, result is valid as a constexpr.

Example 4: When both seem to work

const int a = 100;
constexpr int b = 100;

Both are fine here. The choice depends on intent:

  • use const if you only mean read-only
  • use constexpr if you want compile-time constant semantics

Example 5: Compile-time required context

constexpr int size = 5;
int arr[size];

This works because size is a constant expression.

A plain const variable may or may not work depending on context and standard rules, but constexpr clearly expresses compile-time intent.

Step by Step Execution

Consider this example:

#include <iostream>

constexpr int add(int a, int b) {
    return a + b;
}

int main() {
    const int x = 10;
    constexpr int y = 20;
    constexpr int z = add(2, 3);

    std::cout << x << ' ' << y << ' ' << z << '\n';
}

Step by step

1. The compiler sees constexpr int add(int a, int b)

This tells the compiler that add can be evaluated at compile time if its arguments are constant expressions.

2. const int x = 10;

  • x is read-only
  • it cannot be reassigned
  • this line does not primarily promise compile-time use; it promises immutability

3. constexpr int y = 20;

  • y is read-only
  • y is known at compile time
  • it can be used where a constant expression is required

4. constexpr int z = add(2, 3);

  • 2 and 3 are compile-time constants
  • add(2, 3) is computed during compilation
  • z becomes 5

5. std::cout << x << ' ' << y << ' ' << z

At runtime, the program prints the values. But some of the work, especially computing z, was already done at compile time.

Important nuance

A constexpr function can also run at runtime if you pass runtime values:

constexpr int square(int x) {
    return x * x;
}

int n;
std::cin >> n;
int result = square(n); // valid, but evaluated at runtime

So constexpr on a function means can be compile-time evaluated, not must always be.

Real World Use Cases

When const is useful

Read-only configuration loaded at runtime

const std::string filePath = readConfigFilePath();

The path is not known during compilation, but you still want to prevent accidental modification.

Function parameters that should not change

void printMessage(const std::string& message);

This tells readers and the compiler that the function will not modify message.

Protecting member functions and objects

class User {
public:
    std::string getName() const;
};

Here, const is part of API design and correctness.

When constexpr is useful

Compile-time constants

constexpr double pi = 3.141592653589793;

Useful for math, geometry, and other fixed values.

Array sizes and fixed limits

constexpr int maxUsers = 100;

Compile-time helper functions

constexpr int bufferSize(int kb) {
    return kb * 1024;
}

Template and metaprogramming contexts

template <int N>
struct Buffer {};

constexpr int size = 8;
Buffer<size> b;

Template arguments like size must be compile-time constants.

When both ideas matter

Sometimes you want a value that is both:

  • read-only
  • guaranteed compile-time

That is exactly what constexpr gives you for variables.

Take Quiz

Real Codebase Usage

In real projects, developers usually choose based on intent.

Common pattern: use const for runtime immutability

const auto userId = request.getUserId();
const auto timeout = config.readTimeout();

These values come from runtime data, so constexpr is not possible.

Common pattern: use constexpr for true constants

constexpr int maxRetries = 3;
constexpr char apiVersion[] = "v1";

These are fixed program constants and may be used in compile-time contexts.

Guard clauses and validation

void connect(int port) {
    constexpr int minPort = 1;
    constexpr int maxPort = 65535;

    if (port < minPort || port > maxPort) {
        throw std::out_of_range("invalid port");
    }
}

This makes limits explicit and safe.

Class constants

class Math {
public:
    static constexpr double pi = 3.141592653589793;
};

Real codebases often use static constexpr for values shared by all instances.

Compile-time helper utilities

constexpr bool isPowerOfTwo(unsigned int x) {
    return x > 0 && (x & (x - 1)) == 0;
}

These functions are useful in libraries where values may be known at compile time in some places and only at runtime in others.

Rule of thumb in production code

  • If the value may depend on runtime input, use const.
  • If the value is truly fixed and compile-time meaningful, use constexpr.
  • If both are possible, prefer constexpr when compile-time semantics are useful and intentional.

Common Mistakes

1. Thinking const always means compile-time constant

Broken assumption:

int getValue();
const int x = getValue();

x is read-only, but its value is not known at compile time.

How to avoid it

Ask:

  • Is this just immutable?
  • Or does the compiler need to know it during compilation?

2. Using constexpr with a runtime value

Broken code:

int n = 10;
constexpr int x = n; // error

Why it fails

n is not a constant expression.

Fix

constexpr int n = 10;
constexpr int x = n;

3. Assuming constexpr functions only run at compile time

Broken assumption:

constexpr int doubleValue(int x) {
    return x * 2;
}

int n;
std::cin >> n;
int result = doubleValue(n);

This is valid. The function runs at runtime here because n is only known at runtime.

How to avoid it

Remember: constexpr function means eligible for compile-time evaluation.

4. Using const when compile-time use is required

Broken code:

const int size = getSize();
// int arr[size]; // may fail or be non-portable depending on context

Fix

Use constexpr if the size must be known at compile time.

constexpr int size = 10;
int arr[size];

5. Forgetting that const has many uses beyond variables

Beginners sometimes think this topic is only about constants, but const also applies to:

  • references
  • pointers
  • member functions
  • objects

Example:

void show(const std::string& name);

This is about preventing modification, not compile-time evaluation.

Comparisons

const vs constexpr

Featureconstconstexpr
Prevents modification after initializationYesYes
Requires compile-time valueNoYes
Can use runtime initializationYesNo
Can be used where constant expression is requiredNot guaranteedYes
Best meaningRead-onlyCompile-time constant

Variables: when to choose

SituationPreferred choiceWhy
Value comes from user input or file configconstIt is runtime data
Fixed mathematical or program constantconstexprKnown during compilation
You only want to avoid reassignmentconstSimpler and accurate
You need compile-time use in templates or constant expressionsconstexprRequired by the language

const vs #define

Featureconst / constexpr#define
Type-safeYesNo
ScopedYesNo
Checked by compilerYesNo textual macro only
Preferred in modern C++YesUsually yes

constexpr vs consteval

Featureconstexprconsteval
Can run at compile timeYesYes
Must run at compile timeNoYes
Beginner use caseCommonLess common

consteval is stricter, but for most constant values and functions, constexpr is the practical tool.

Take Quiz

Cheat Sheet

Quick rules

  • const = read-only after initialization
  • constexpr = compile-time constant
  • Every constexpr variable is effectively const
  • Not every const variable is constexpr

Syntax

const int a = 10;
constexpr int b = 10;

constexpr int square(int x) {
    return x * x;
}

Use const when

  • the value is decided at runtime
  • you want to prevent accidental changes
  • you are working with parameters, references, pointers, or member functions

Use constexpr when

  • the value is known during compilation
  • the value may be used in constant-expression contexts
  • you want compile-time computation

Common examples

const int port = readPort();
constexpr int maxConnections = 100;
constexpr int area = square(4);

Decision shortcut

  • Can the value depend on runtime input?
    • Yes -> const
    • No -> maybe constexpr
  • Does the compiler need the value at compile time?
    • Yes -> constexpr

Important edge case

A constexpr function:

  • can run at compile time with constant-expression arguments
  • can also run at runtime with normal arguments

FAQ

Is constexpr always better than const?

No. Use constexpr when a compile-time constant is intended. Use const when you only need a read-only value, especially if it comes from runtime data.

Is every constexpr variable also const?

Yes, a constexpr variable is immutable and acts like a constant.

Can a const variable be initialized at runtime?

Yes. That is one of the main differences. const does not require compile-time initialization.

Can a constexpr function be called at runtime?

Yes. If the arguments are not constant expressions, the function can still execute at runtime.

Should I use constexpr for all fixed numeric constants?

Usually yes, if they are truly compile-time constants and that meaning is useful in the code.

Why not just use #define for constants?

Because constexpr and const are type-safe, scoped, and checked by the compiler.

Can I use both const and constexpr together?

For variables, constexpr already implies const-like immutability, so writing both is usually unnecessary.

When does const matter beyond variables?

It is heavily used with references, pointers, member functions, and APIs to express that something should not be modified.

Take Quiz

Mini Project

Description

Build a small C++ program that demonstrates the difference between runtime read-only values and compile-time constants. This project is useful because many real programs contain both kinds of data: configuration read at runtime and fixed limits or formulas known at compile time.

Goal

Create a program that uses const for runtime values and constexpr for compile-time values, then prints results showing the difference.

Requirements

[ "Create a constexpr function that performs a simple calculation.", "Declare at least one constexpr variable initialized with a compile-time value.", "Read or simulate a runtime value and store it in a const variable.", "Print both the compile-time and runtime-based results.", "Use clear variable names that show why each keyword was chosen." ]

Take Quiz

Keep learning

Related questions

View more