Skip to content

Commit 567e3e6

Browse files
committed
P0595R2 std::is_constant_evaluated()
1 parent 12935b8 commit 567e3e6

File tree

4 files changed

+87
-19
lines changed

4 files changed

+87
-19
lines changed

source/basic.tex

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5667,15 +5667,9 @@
56675667
\pnum
56685668
\indextext{initialization!static object@\tcode{static} object}%
56695669
\indextext{initialization!constant}%
5670-
A \defn{constant initializer} for a variable or temporary object \tcode{o}
5671-
is an initializer whose full-expression is a
5672-
constant expression, except that if \tcode{o} is an object,
5673-
such an initializer may also invoke constexpr constructors
5674-
for \tcode{o} and its subobjects even if those objects are of non-literal class
5675-
types. \begin{note} Such a class may have a non-trivial destructor. \end{note}
56765670
\defnx{Constant initialization}{constant initialization} is performed
56775671
if a variable or temporary object with static or thread storage duration
5678-
is initialized by a constant initializer for the entity.
5672+
is initialized by a constant initializer\iref{expr.const} for the entity.
56795673
\indextext{initialization!runtime}%
56805674
If constant initialization is not performed, a variable with static
56815675
storage duration\iref{basic.stc.static} or thread storage

source/expressions.tex

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6488,6 +6488,26 @@
64886488
conditional-expression
64896489
\end{bnf}
64906490

6491+
\pnum
6492+
A \defn{constant initializer} for a variable or temporary object \tcode{o} is
6493+
an initializer for which interpreting its full-expression
6494+
as a \grammarterm{constant-expression} results in a constant expression,
6495+
except that if \tcode{o} is an object,
6496+
such an initializer may also invoke constexpr constructors
6497+
for \tcode{o} and its subobjects
6498+
even if those objects are of non-literal class types.
6499+
\begin{note}
6500+
Such a class may have a non-trivial destructor.
6501+
Within this evaluation,
6502+
\tcode{std::is_constant_evaluated()}\iref{meta.is_constant_evaluated}
6503+
returns \tcode{true}.
6504+
\end{note}
6505+
A variable is
6506+
\defnx{usable in constant expressions}{usable in constant expression} after
6507+
its initializing declaration is encountered if it is a constexpr variable, or
6508+
it is of reference type or of const-qualified integral or enumeration type, and
6509+
its initializer is a constant initializer.
6510+
64916511
\pnum
64926512
An expression \tcode{e} is a \defnadj{core constant}{expression}
64936513
unless the evaluation of \tcode{e}, following the rules of the abstract
@@ -6540,17 +6560,6 @@
65406560
to a complete non-volatile const object with a preceding initialization,
65416561
initialized with a constant expression, or
65426562

6543-
\item
6544-
a non-volatile glvalue that refers to a subobject of a string
6545-
literal\iref{lex.string}, or
6546-
6547-
\item
6548-
a non-volatile glvalue that refers to a non-volatile object
6549-
defined with \tcode{constexpr} or
6550-
a template parameter object\iref{temp.param},
6551-
or that refers to a non-mutable subobject
6552-
of such an object, or
6553-
65546563
\item
65556564
a non-volatile glvalue of literal type that refers to a non-volatile object
65566565
whose lifetime began within the evaluation of \tcode{e};
@@ -6579,7 +6588,7 @@
65796588

65806589
\begin{itemize}
65816590
\item
6582-
it is initialized with a constant expression or
6591+
it is usable in constant expressions or
65836592

65846593
\item
65856594
its lifetime began within the evaluation of \tcode{e};
@@ -6835,6 +6844,43 @@
68356844
It is unspecified whether the value of \tcode{f()} will be \tcode{true} or \tcode{false}.
68366845
\end{example} \end{note}%
68376846

6847+
\pnum
6848+
An expression or conversion \tcode{e} is \defn{manifestly constant-evaluated}
6849+
if it is:
6850+
\begin{itemize}
6851+
\item a \grammarterm{constant-expression}, or
6852+
\item the condition of a constexpr if statement\iref{stmt.if}, or
6853+
\item the initializer of a constexpr variable\iref{dcl.constexpr}, or
6854+
\item an immediate invocation, or
6855+
\item a \grammarterm{constraint-expression}\iref{temp.constr.decl}
6856+
(possibly one formed from the \grammarterm{constraint-logical-or-expression}
6857+
of a \grammarterm{requires-clause}), or
6858+
\item the initializer of a variable
6859+
that is usable in constant expressions or
6860+
has constant initialization.\footnote{Testing this condition
6861+
may involve a trial evaluation of its initializer as described above.}
6862+
\begin{example}
6863+
\begin{codeblock}
6864+
template<bool> struct X {};
6865+
X<std::is_constant_evaluated()> x; // type X<true>
6866+
int y;
6867+
const int a = std::is_constant_evaluated() ? y : 1; // dynamic initialization to 1
6868+
double z[a]; // ill-formed: "a" is not "usable in constant expressions"
6869+
const int b = std::is_constant_evaluated() ? 2 : y; // static initialization to 2
6870+
int c = y + (std::is_constant_evaluated() ? 2 : y); // dynamic initialization to y+y
6871+
6872+
constexpr int f() {
6873+
const int n = std::is_constant_evaluated() ? 13 : 17; // n == 13
6874+
int m = std::is_constant_evaluated() ? 13 : 17; // m might be 13 or 17 (see below)
6875+
char arr[n] = {}; // char[13]
6876+
return m + sizeof(arr);
6877+
}
6878+
int p = f(); // m == 13; initialized to 26
6879+
int q = p + f(); // m == 17 for this call; initialized to 56
6880+
\end{codeblock}
6881+
\end{example}
6882+
\end{itemize}
6883+
68386884
\pnum
68396885
\indextext{expression!potentially constant evaluated}%
68406886
An expression is \defn{potentially constant evaluated}

source/support.tex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,8 @@
599599
\tcode{<functional>} \\ \rowsep
600600
\defnlibxname{cpp_lib_is_aggregate} & \tcode{201703L} &
601601
\tcode{<type_traits>} \\ \rowsep
602+
\defnlibxname{cpp_lib_is_constant_evaluated} & \tcode{201811L} &
603+
\tcode{<type_traits>} \\ \rowsep
602604
\defnlibxname{cpp_lib_is_final} & \tcode{201402L} &
603605
\tcode{<type_traits>} \\ \rowsep
604606
\defnlibxname{cpp_lib_is_invocable} & \tcode{201703L} &

source/utilities.tex

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15744,6 +15744,9 @@
1574415744
inline constexpr bool disjunction_v = disjunction<B...>::value;
1574515745
template<class B>
1574615746
inline constexpr bool negation_v = negation<B>::value;
15747+
15748+
// \ref{meta.is_constant_evaluated}, constexpr evaluation
15749+
constexpr bool is_constant_evaluated() noexcept;
1574715750
}
1574815751
\end{codeblock}
1574915752

@@ -17394,6 +17397,29 @@
1739417397
to either \tcode{endian::big} or \tcode{endian::little}.
1739517398
\end{itemdescr}
1739617399

17400+
\rSec2[meta.is_constant_evaluated]{Constexpr evaluation context}
17401+
\begin{itemdecl}
17402+
constexpr bool is_constant_evaluation() noexcept;
17403+
\end{itemdecl}
17404+
17405+
\begin{itemdescr}
17406+
\pnum
17407+
\returns \tcode{true} if and only if evaluation of the call occurs
17408+
within the evaluation of an expression or conversion
17409+
that is manifestly constant-evaluated\iref{expr.const}.
17410+
17411+
\pnum
17412+
\begin{example}
17413+
constexpr void f(unsigned char *p, int n) {
17414+
if (std::is_constant_evaluated()) { // should not be a constexpr if statement
17415+
for (int k = 0; k<n; ++k) p[k] = 0;
17416+
} else {
17417+
memset(p, 0, n); // not a core constant expression
17418+
}
17419+
}
17420+
\end{example}
17421+
\end{itemdescr}
17422+
1739717423
\rSec1[ratio]{Compile-time rational arithmetic}
1739817424

1739917425
\rSec2[ratio.general]{In general}

0 commit comments

Comments
 (0)