Quick Links: |
Provide macros related to compile-time evaluation. More...
BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED | true during constant evaluation |
BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE | undefined if inactive |
BSLS_CONSTEVAL_CONSTEXPR | constexpr if IS_ACTIVE defined |
BSLS_CONSTEVAL_CONSTEXPR_MEMBER | constexpr if IS_ACTIVE , else const |
std::is_constant_evaluated()
function will be used. On some platforms where that is unavailable a compiler intrinsic will be used instead. Finally, when no option for this functionality is available the BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED
macro will expand to nothing and BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE
will not be defined. To ease writing declarations of functions where there is conditionally available compile-time behavior, BSLS_CONSTEVAL_CONSTEXPR
is defined to be equivalent to constexpr
if BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE
is defined. BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED
This macro expands to std::is_constant_evaluated
when it is available, or to a compiler intrinsic with equivalent functionality if available, else, it expands to nothing.BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE
This macro is defined to 1 if BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED
can be used to identify compile-time evaluation, and is undefined otherwise.BSLS_CONSTEVAL_CONSTEXPR
This macro is defined to be constexpr
if BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE
is defined, otherwise it is defined as empty.BSLS_CONSTEVAL_CONSTEXPR_MEMBER
This macro is defined to be constexpr
if BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE
is defined; otherwise it is const
. This should be applied to variables and member variables that should be initialized by a function that is BSLS_CONSTEVAL_CONSTEXPR
.stdout
. BSLS_CONSTEVAL_CONSTEXPR int compute() // Return '23' if the invocation is evaluated at compile time and that // is detectable, otherwise print a diagnostic message to 'stdout' and // return '17'. { #ifdef BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE if (BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED) { return 23; // RETURN } #endif printf("Computing value\n"); return 17; // RETURN }
test1
function to invoke compute
in different contexts. This function can be evaluated both at runtime and at compile time without errors. Below, this function is evaluated in both cases, and the difference in behavior is observed. void test1() // Invoke 'compute' in both a const and non-const initialization, // verifying the expected results. { int i = compute(); BSLS_CONSTEVAL_CONSTEXPR_MEMBER int j = compute(); #ifdef BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE ASSERT(17 == i); ASSERT(23 == j); #else ASSERT(17 == i); ASSERT(17 == j); #endif }
17 == i
or 17 == j
, compute
will write "Computing value/n" to stdout
. So, this message will be written once or twice depending on whether BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE
is defined. The variable j
will always be const
, and on platforms where the compute
function supports being constexpr
, i.e. those where it can use BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED
to suppress its use of standard output, j
will also be constexpr
and its value will be computed at compile time. constexpr
function, the other of which takes advantage of runtime optimizations (such as hardware acceleration, exceptions, or non-'constexpr' third-party libraries) that are not available at compile time on any platform: int runtimeCompute(int input); BSLS_KEYWORD_CONSTEXPR int compiletimeCompute(int input); // Return a complicated computed value based on the specified 'input'.
compiletimeCompute
function is likely used to initialize many const
and constexpr
variables, but also potentially used in many runtime-only expressions, or as part of other constexpr
functions that are themselves sometimes used at runtime. The runtimeCompute
function, similarly, is likely used in many contexts that could become constexpr
or be evaluated at compile time, but is hindering that due to itself not being constexpr
. compiletimeCompute
and runtimeCompute
to both have improved performance wherever they might be used by moving their implementations to separate functions: int runtimeComputeImpl(int input); // Return a complicated computed value based on the specified 'input'. BSLS_KEYWORD_CONSTEXPR int compiletimeComputeImpl(int input); // Return a complicated computed value based on the specified 'input'.
compiletimeCompute
we can provide a new implementation that will use the better runtime algorithm when possible, while remaining constexpr
on all of the platforms where it previously was constexpr
(i.e., without changing its declaration): BSLS_KEYWORD_CONSTEXPR int compiletimeCompute(int input) // Return a complicated computed value based on the specified 'input'. { #ifdef BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE if (!BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED) { return runtimeComputeImpl(input); // RETURN } #endif // BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE return compiletimeComputeImpl(input); }
compiletimeCompute
at runtime, both within and outside of other constexpr
functions, will get the benefits of an improved algorithm without any need for change. runtimeCompute
can be improved to be opportunistically constexpr
by taking advantage of BSLS_CONSTEVAL_CONSTEXPR
, potentially allowing some already existing expressions to be compile time evaluated on more modern platforms: BSLS_CONSTEVAL_CONSTEXPR int runtimeCompute(int input) // Return a complicated computed value based on the specified 'input'. { #ifdef BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE if (BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED) { return compiletimeComputeImpl(input); // RETURN } #endif // BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE return runtimeComputeImpl(input); }
runtimeCompute
can continue to use it at runtime with no changes, occasionally getting the benefits of the compile-time algorithm. When using runtimeCompute
to initialize a variable, the compile-time behavior can be forced by annotating the variable with BSLS_CONSTEVAL_CONSTEXPR_MEMBER
.