Difference between revisions of "cpp/language/consteval"
(change to if consteval as is_constant_evaluated() is always false in constexpr contexts) |
m (→Example: fix error message) |
||
Line 61: | Line 61: | ||
// With consteval we have a guarantee that the function will be evaluated at compile-time. | // With consteval we have a guarantee that the function will be evaluated at compile-time. | ||
consteval unsigned combination(unsigned m, unsigned n) { | consteval unsigned combination(unsigned m, unsigned n) { | ||
− | // if !consteval { throw std::logic_error("Non-constexpr call to | + | // if !consteval { throw std::logic_error("Non-constexpr call to combination"); } // always OK in immediate functions |
return factorial(n)/factorial(m)/factorial(n-m); | return factorial(n)/factorial(m)/factorial(n-m); | ||
} | } |
Revision as of 09:58, 17 January 2022
consteval
- specifies that a function is an immediate function, that is, every call to the function must produce a compile-time constant
Contents |
Explanation
The consteval
specifier declares a function or function template to be an immediate function, that is, every potentially evaluated call (i.e. call out of an unevaluated context) to the function must (directly or indirectly) produce a compile time constant expression.
An immediate function is a constexpr function, and must satisfy the requirements applicable to constexpr functions or constexpr constructors, as the case may be. Same as constexpr
, a consteval
specifier implies inline
. However, it may not be applied to destructors, allocation functions, or deallocation functions.
At most one of the constexpr
, consteval
, and constinit
specifiers is allowed to appear within the same sequence of declaration specifiers. If any declaration of a function or function template contains a consteval
specifier, then all declarations of that function or function template must contain that specifier.
A potentially evaluated invocation of an immediate function whose innermost non-block scope is not a function parameter scope of an immediate function or the true-branch of a consteval if statement(since C++23) must produce a constant expression; such an invocation is known as an immediate invocation.
consteval int sqr(int n) { return n*n; } constexpr int r = sqr(100); // OK int x = 100; int r2 = sqr(x); // Error: Call does not produce a constant consteval int sqrsqr(int n) { return sqr(sqr(n)); // Not a constant expression at this point, but OK } constexpr int dblsqr(int n) { return 2*sqr(n); // Error: Enclosing function is not consteval // and sqr(n) is not a constant }
An identifier expression that denotes an immediate function may only appear within a subexpression of an immediate invocation or within an immediate function context (i.e. a context mentioned above, in which a call to an immediate function needs not to be a constant expression). A pointer or reference to an immediate function can be taken but cannot escape constant expression evaluation:
consteval int f() { return 42; } consteval auto g() { return &f; } consteval int h(int (*p)() = g()) { return p(); } constexpr int r = h(); // OK constexpr auto e = g(); // ill-formed: a pointer to an immediate function is // not a permitted result of a constant expression
Keywords
Example
#include <iostream> // This function might be evaluated at compile-time, if the input // is known at compile-time. Otherwise, it is executed at run-time. constexpr unsigned factorial(unsigned n) { return n < 2 ? 1 : n * factorial(n - 1); } // With consteval we have a guarantee that the function will be evaluated at compile-time. consteval unsigned combination(unsigned m, unsigned n) { // if !consteval { throw std::logic_error("Non-constexpr call to combination"); } // always OK in immediate functions return factorial(n)/factorial(m)/factorial(n-m); } static_assert(factorial(6) == 720); static_assert(combination(4,8) == 70); int main(int argc, const char*[]) { constexpr unsigned x{factorial(4)}; std::cout << x << '\n'; [[maybe_unused]] unsigned y = factorial(argc); // OK // unsigned z = combination(argc, 7); // error: 'argc' is not a constant expression }
Output:
24
See also
constexpr specifier(C++11)
|
specifies that the value of a variable or function can be computed at compile time |
constinit specifier(C++20)
|
asserts that a variable has static initialization, i.e. zero initialization and constant initialization |
constant expression | defines an expression that can be evaluated at compile time |