Ch7.2: constexpr Object Generation

Overview

A constexpr function can build objects at compile time. In this chapter, we generate a lookup table of powers of ten using a loop inside a constexpr function, return the table, and force the compiler to compute it during compilation.

This technique is useful for precomputed tables such as powers of ten, digit conversion tables, and other fixed data that should not be computed at runtime.

1. Determining how many powers of ten fit

We use std::uint_least64_t to avoid overflow. The number of safe powers of ten is given by:


constexpr std::size_t pow10_count =
    ::std::numeric_limits<::std::uint_least64_t>::digits10 + 1;

For 64‑bit integers, this is typically 19 (10⁰ through 10¹⁸).

2. Generating the table with a constexpr function

A constexpr function may contain loops. We use this to fill a ::fast_io::array with powers of ten. The return type is auto, so the compiler deduces the array type.


constexpr auto make_pow10()
{
    ::fast_io::array<::std::uint_least64_t, pow10_count> arr{};
    ::std::uint_least64_t value{1};

    for(std::size_t i{}; i != pow10_count; ++i)
    {
        arr[i] = value;
        value *= 10;
    }

    return arr;
}

This function builds the entire table at compile time.

3. Forcing compile‑time evaluation

To force the compiler to compute the table during compilation, define an inline constexpr global variable:


inline constexpr auto pow10_table = make_pow10();

A constexpr variable forces its initializer to be evaluated at compile time. If the initializer calls a constexpr function, the compiler must execute that function during compilation.

If the computation cannot be completed at compile time, the compilation fails. This happens when:

Because the variable is inline, it can be placed in a header without causing duplicate symbol errors.

4. Using the table in main()


int main()
{
    using namespace ::fast_io::iomnp;
    println(pow10_table[0]);  // 1
    println(pow10_table[1]);  // 10
    println(pow10_table[5]);  // 100000
    println(pow10_table[18]); // 10^18 (on 64-bit)
}

All values are precomputed and stored directly in the program image.

Key takeaways