Const & constexpr correctness

Core semantics7 standards

Logical constness and the growing compile-time subset.

constexpr v1: single-return functions only — compile-time constants without macros. const methods define logical constness; mutable covers caches.

constexpr int sq(int x) { return x * x; }   // all C++11 allows
struct Table {
  int lookup(Key k) const;        // logical const
  mutable std::mutex m_;          // locking doesn't break constness
};

Relaxed constexpr: loops, locals, mutation. Compile-time code starts looking like normal code.

constexpr int pop(unsigned v) {
  int n = 0;
  for (; v; v >>= 1) n += v & 1;
  return n;
}

if constexpr brings compile-time branching into regular functions; lambdas are implicitly constexpr where possible.

The big leap: consteval (must run at compile time), constinit (compile-time init, runtime mutable), constexpr virtuals, try, dynamic allocation — std::vector and std::string work in constant evaluation.

consteval int parse_version(std::string_view s);   // compile-time only
constinit std::atomic<int> counter{0};             // no SIOF, still mutable
constexpr auto sorted = [] {
  std::array a{3, 1, 2};
  std::ranges::sort(a);
  return a;
}();

if consteval replaces std::is_constant_evaluated() (and can call consteval functions); constexpr unique_ptr; static constexpr allowed inside constexpr functions.

constexpr int fast_log2(unsigned v) {
  if consteval { return portable_log2(v); }
  else         { return std::countl_zero(v) ^ 31; }
}

Constant evaluation approaches completeness: static_cast from void*, placement new, and thrown-and-caught exceptions all work at compile time — and reflection is itself a consteval library.

constexpr int checked(int x) {
  try { return risky(x); }               // constexpr exceptions (C++26)
  catch (const std::exception&) { return -1; }
}
C++29direction · not adopted

Direction: the remaining gaps (more of the library marked constexpr, compile-time I/O-adjacent facilities) keep shrinking release by release.

C++26 per the final working draft; C++29 rows are proposals and direction, not adopted features.