| "A constexpr function can very well take an input, and it can invoke UB based on the runtime value of that input.
" No, it cannot. It is not constant if it does that. As such, it cannot be used in in any context that requires a constant expression.
It explicitly says the operations in a constexpr may not produce undefined behavior. That isn't "may not produce undefined behavior except if you pass the wrong values at runtime or don't evaluate it".
It says:
"An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (6.8.1), would evaluate one of the following expressions: … an operation that would have undefined behavior " In your case, the evaluation would evaluate (at runtime) an operation that would have undefined behavior. It is true that where you do not require a constant expression, it does not require it be constexpr at all, but the question is whether an expression that produces undefined behavior is constexpr is "no". The standard even clarified this to say that foo is simply considered non-constant in your example (IE it's not constexpr ). IE see defect report 695 "The consensus of the CWG was that an expression like 1/0 should simply be considered non-constant; any diagnostic would result from the use of the expression in a context requiring a constant expression.
" In your example, foo is non-constant as used. It is not constexpr. |
Still, it should be noted that even code that looks identical to a core constant expression can display certain kinds of UB if invoked at runtime, per the standard. For example, if the code is using certain STL classes or threading constructs in a way that is UB, it can still be considered a core constant expression. Additionally, the code may be well defined when used in a single-threaded context, but become UB when used in multi-threaded contexts, say if two threads are accessing an object member concurrently without the right barriers.
Here is an example on godbolt. Notice that bar() and baz() are defined the same way in the static_assert block and the runtime block, yet executing them constitutes UB in one case but not the other.
https://godbolt.org/z/3q5sTGe4j