C/C++ Arena

Step 7 of 7

Attributes, consteval and constinit

Modern C++ adds small annotations that tell the compiler what you mean, so it can catch mistakes or optimize, without changing what correct code does.

Attributes

Attributes go in double square brackets:

Attribute Meaning
[[nodiscard]] warn if a caller ignores the return value (an error code, a newly allocated object)
[[maybe_unused]] don't warn that this variable or parameter is unused
[[fallthrough]] this case deliberately continues into the next one
[[deprecated("use x")]] warn anyone who still calls this
[[likely]] / [[unlikely]] (C++20) a hint about which branch usually runs

[[nodiscard]] is the one worth adding everywhere it applies. [[nodiscard]] bool save(const Config&); turns save(cfg); (forgetting to check) into a compiler warning.

constexpr, consteval, constinit

#include <iostream>

consteval int kib(int n) { return n * 1024; }            // compile time only
constexpr int square(int n) { return n * n; }           // either
constinit int buffer_size = kib(4);                     // set before main runs; still changeable

[[nodiscard]] bool resize(int& size, int wanted) {
    if (wanted <= 0) return false;
    size = wanted;
    return true;
}

int main() {
    static_assert(kib(2) == 2048);
    int n = 5;
    std::cout << square(n) << " " << buffer_size << "\n";   // square at run time here
    if (!resize(buffer_size, kib(8))) return 1;
    std::cout << buffer_size << "\n";
}
25 4096
8192

Calling kib(n) with the run-time variable n would not compile, and writing resize(buffer_size, 100); without checking the result gets a warning.

The classic use: switching on strings

A switch only works on integers, and each case needs a compile-time constant. A consteval hash turns fixed strings into constants, and a constexpr version of the same hash handles the run-time input.

Your turn: write fnv1a(s) as a constexpr 32-bit FNV-1a hash (start from 2166136261; for each character, XOR in the character as an unsigned char, then multiply by 16777619), id_of(s) as a consteval wrapper around it, and command_code(cmd), which switches on fnv1a(cmd) with case id_of("start"), id_of("stop") and id_of("pause") returning 1, 2 and 3, and -1 for anything else. Mark command_code [[nodiscard]].

Previous: std::span