Compile time
A C++ program has two lives: compile time, while the compiler builds it, and run time, while the CPU runs it. constexpr in front of sq means the compiler may run sq itself, during the build.
constexpr int N = sq(4); declares a compile-time constant. Its value must be a constant expression, so the compiler itself calls sq(4) while building and gets 16. No CPU time is spent on it later.
The compiler writes 16 straight into the program wherever N is used. When app runs, there is nothing left to work out: N is simply 16, and N can never change.
static_assert(N == 16); is a check the compiler makes while building. It holds, so the build goes on. Were it false, the build would stop with 'static assertion failed' and no program would be made.
An array's size must be known at compile time. N is a constant expression, so int buf[N] = {}; makes room for exactly 16 ints, all 0. A value that only exists at run time could not size it.
Run time
Now you type ./app. Only now does argc exist: 1, the program's own name. const int k = argc * 3; works out 3 while the program runs, then locks it. const means read-only, not known early.
Add k = 5; after line 8 and the build fails: the compiler reports an assignment to a read-only variable. const is checked at compile time, before anything runs, so k stays 3.
Try constexpr int M = sq(argc); and it does not compile. argc only exists once the program runs, and the compiler cannot wait for it. const accepts a run-time value; constexpr demands a compile-time one.
sq(k) calls the same constexpr function with a run-time value. Now it is an ordinary call: the CPU works out 3 * 3 = 9 while the program runs. constexpr on a function means may, not must.
main returns sq(k) + buf[0], 9 + 0, so the exit status is 9. Run ./app a b and argc is 3, k is 9 and the status is 81, with no rebuild. N stays 16 in every run.
Choosing
Make values const by default when they should not change after they are set. Use constexpr when the compiler can work the value out: sizes, tables, limits. C++20's consteval goes further: such a function must run at compile time.
What happens
;; step 1/11 · constexpr-fn
line 1 constexpr int sq(int n) {
line 2 return n * n;
constexpr 'can be evaluated at compile time'
compile time the compiler builds app from app.cpp
run time the CPU runs app
Compile time and run time: the compiler (g++ or clang++) turns app.cpp into the program file app; running ./app happens later, as often as you like. Values a program reads when it runs, such as argc or user input, cannot be known while it is built. The standard guarantees that N's value is known to the compiler, so it can be used where a constant expression is required. Whether N also gets a slot in memory is up to the compiler; in practice 16 is written into the machine code wherever N is used.