Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/language/consteval"

From cppreference.com
< cpp‎ | language
m (Example)
(Updated the links to 'potentially-evaluated expressions'.)
Line 5: Line 5:
 
===Explanation===
 
===Explanation===
  
The {{tt|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 {{rlp|expressions#Unevaluated expressions|unevaluated context}}) to the function must (directly or indirectly) produce a compile time {{rlp|constant expression}}.
+
The {{tt|consteval}} specifier declares a function or function template to be an ''immediate function'', that is, every {{rlp|expressions#Potentially-evaluated expressions|potentially-evaluated}} call to the function must (directly or indirectly) produce a compile time {{rlp|constant expression}}.
  
An immediate function is a constexpr function, and must satisfy the requirements applicable to {{rlp|constexpr|constexpr functions or constexpr constructors}}, as the case may be. Same as {{tt|constexpr}}, a {{tt|consteval}} specifier implies {{tt|inline}}. However, it may not be applied to destructors, allocation functions, or deallocation functions.
+
An immediate function is a {{rlp|constexpr#constexpr function|constexpr function}}, subject to its requirements as the case may be. Same as {{tt|constexpr}}, a {{tt|consteval}} specifier implies {{tt|inline}}. However, it may not be applied to destructors, allocation functions, or deallocation functions.
  
 
At most one of the {{tt|constexpr}}, {{tt|consteval}}, and {{tt|constinit}} specifiers is allowed to appear within the same sequence of declaration specifiers. If any declaration of a function or function template contains a {{tt|consteval}} specifier, then all declarations of that function or function template must contain that specifier.
 
At most one of the {{tt|constexpr}}, {{tt|consteval}}, and {{tt|constinit}} specifiers is allowed to appear within the same sequence of declaration specifiers. If any declaration of a function or function template contains a {{tt|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 {{rlp|scope#Function parameter scope|function parameter scope}} of an immediate function {{rev inl|since=c++23| or the true-branch of a {{rlp|if#Consteval if|consteval if statement}}}} must produce a constant expression; such an invocation is known as an ''immediate invocation''.
+
A {{rlp|expressions#Potentially-evaluated expressions|potentially-evaluated}} invocation of an immediate function whose innermost non-block scope is not a {{rlp|scope#Function parameter scope|function parameter scope}} of an immediate function {{rev inl|since=c++23| or the true-branch of a {{rlp|if#Consteval if|consteval if statement}}}} must produce a constant expression; such an invocation is known as an ''immediate invocation''.
  
 
{{source|1=<!-- from P1073R3 -->
 
{{source|1=<!-- from P1073R3 -->
consteval int sqr(int n) {
+
consteval int sqr(int n)
  return n*n;
+
{
 +
    return n*n;
 
}
 
}
 
constexpr int r = sqr(100); // OK
 
constexpr int r = sqr(100); // OK
Line 22: Line 23:
 
int r2 = sqr(x);            // Error: Call does not produce a constant
 
int r2 = sqr(x);            // Error: Call does not produce a constant
  
consteval int sqrsqr(int n) {
+
consteval int sqrsqr(int n)
 +
{
 
   return sqr(sqr(n));      // Not a constant expression at this point, but OK
 
   return sqr(sqr(n));      // Not a constant expression at this point, but OK
 
}
 
}
  
constexpr int dblsqr(int n) {
+
constexpr int dblsqr(int n)
  return 2*sqr(n);         // Error: Enclosing function is not consteval
+
{
 +
    return 2 * sqr(n);     // Error: Enclosing function is not consteval
 
                             // and sqr(n) is not a constant
 
                             // and sqr(n) is not a constant
 
}
 
}
Line 51: Line 54:
 
===Example===
 
===Example===
 
{{example
 
{{example
  |
+
|
  | code=
+
|code=
 
#include <iostream>
 
#include <iostream>
  
 
// This function might be evaluated at compile-time, if the input
 
// This function might be evaluated at compile-time, if the input
 
// is known at compile-time. Otherwise, it is executed at run-time.
 
// is known at compile-time. Otherwise, it is executed at run-time.
constexpr unsigned factorial(unsigned n) {
+
constexpr unsigned factorial(unsigned n)
 +
{
 
     return n < 2 ? 1 : n * factorial(n - 1);
 
     return n < 2 ? 1 : n * factorial(n - 1);
 
}
 
}
  
 
// With consteval we enforce that the function will be evaluated at compile-time.
 
// With consteval we enforce that the function will be evaluated at compile-time.
consteval unsigned combination(unsigned m, unsigned n) {
+
consteval unsigned combination(unsigned m, unsigned n)
 +
{
 
     return factorial(n) / factorial(m) / factorial(n - m);
 
     return factorial(n) / factorial(m) / factorial(n - m);
 
}
 
}
  
 
static_assert(factorial(6) == 720);
 
static_assert(factorial(6) == 720);
static_assert(combination(4,8) == 70);
+
static_assert(combination(4, 8) == 70);
 
+
int main(int argc, const char*[]) {
+
  
 +
int main(int argc, const char*[])
 +
{
 
     constexpr unsigned x{factorial(4)};
 
     constexpr unsigned x{factorial(4)};
 
     std::cout << x << '\n';
 
     std::cout << x << '\n';
 
+
   
 
     [[maybe_unused]]
 
     [[maybe_unused]]
 
     unsigned y = factorial(argc); // OK
 
     unsigned y = factorial(argc); // OK
 
//  unsigned z = combination(argc, 7); // error: 'argc' is not a constant expression
 
//  unsigned z = combination(argc, 7); // error: 'argc' is not a constant expression
 
}
 
}
  | output=
+
|output=
 
24
 
24
 
}}
 
}}
Line 84: Line 89:
 
===See also===
 
===See also===
 
{{dsc begin}}
 
{{dsc begin}}
{{dsc inc | cpp/language/dsc constexpr}}
+
{{dsc inc|cpp/language/dsc constexpr}}
{{dsc inc | cpp/language/dsc constinit}}
+
{{dsc inc|cpp/language/dsc constinit}}
{{dsc | [[cpp/language/constant expression|constant expression]] | defines an {{rlp|expressions|expression}} that can be evaluated at compile time }}
+
{{dsc|{{rlp|constant expression}}| defines an {{rlp|expressions|expression}} that can be evaluated at compile time}}
 
{{dsc end}}
 
{{dsc end}}
  
 
{{langlinks|es|ja|ru|zh}}
 
{{langlinks|es|ja|ru|zh}}

Revision as of 06:27, 4 December 2022

 
 
C++ language
General topics
Flow control
Conditional execution statements
if
Iteration statements (loops)
for
range-for (C++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++17*)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
explicit (C++11)
static

Special member functions
Templates
Miscellaneous
 
 
  • 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 to the function must (directly or indirectly) produce a compile time constant expression.

An immediate function is a constexpr function, subject to its requirements 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

Notes

Feature-test macro Value Std Feature
__cpp_consteval 201811L (C++20) Immediate functions

Keywords

consteval

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 enforce that the function will be evaluated at compile-time.
consteval unsigned combination(unsigned m, unsigned n)
{
    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[edit]
constinit specifier(C++20) asserts that a variable has static initialization, i.e. zero initialization and constant initialization[edit]
constant expression defines an expression that can be evaluated at compile time