What is the difference between C++11's constexpr and C23's [[reproducible]]?

250 Views Asked by At

C++11 added the constexpr keyword which can be added to functions to specify constant behavior.

C23 added what seems to be identical functionality in the form of the [[reproducible]] tag.

How are these two mechanisms different?

3

There are 3 best solutions below

0
On BEST ANSWER

C++11 added the constexpr keyword which can be added to functions to specify constant behavior.

C23 added what seems to be identical functionality in the form of the [[reproducible]] tag.

How are these two mechanisms different?

Generally speaking, the C++ (or C) constexpr specifier is much stronger than the C [[reproducible]] attribute, and the former has much more extensive semantics and stronger constraints. Moreover, constexpr is part of program semantics, whereas [[reproducible]], as an attribute, serves as optional metadata that a compiler can use or not as it chooses. [[reproducible]] can freely be removed without changing the validity or semantics of the program, provided that a function defined without [[reproducible]] is not called from a scope in which its in-scope declaration carries that attribute.

Considering only facets that apply to both languages, here are some more details:

  • calls to constexpr functions can appear in constant expressions, which implies that they can be evaluated at compile time. The former is not true of reproducible functions, and it is not necessary that it be possible to evaluate calls to reproducible functions at compile time.

  • C++ constexpr functions have limits on their argument and return types, whereas C reproducible functions do not.

  • In some versions of C++, constexpr functions have limits on the kind of statements that can appear in their definitions (goto, labels, ...), whereas C reproducible functions do not.

  • In C++, the definition and all declarations of a function must agree about whether it is a constexpr function. In C, a function defined with the reproducible attribute can safely be redeclared without it, in any translation unit.

  • A C++ constexpr function cannot write to non-local objects, and cannot read most non-local objects. A C [[reproducible]] function is not limited in which objects it may read. A reproducible function may write to non-local objects via pointers provided to it as arguments.

  • Every call to a C++ constexpr function with the same arguments must produce the same return value (if any), whereas two calls to a reproducible function with the same arguments are required to produce the same return value only if the calls are performed one immediately after the other.

Overall, constexpr and [[reproducible]] have some general similarities, but they have very different significance, effects, and purpose. They are nowhere close to "identical". On the other hand, C23 also introduces constexpr to C, with semantics for objects very similar to C++ constexpr. In C, however, constexpr can be applied only to objects, not to functions.

0
On

There are a few, but principally constexpr is intended to refer to compile time evaluation of a function invocation (where applicable) - whereas [[reproducible]] and [[unsequenced]] act more as restrictions on a function which allow for more invasive optimization techniques than would otherwise be legal.

In practice a compiler might treat some aspects of these similarly, but constexpr is more versatile in what it allows, and more lenient in that it can be demoted to act at runtime outside of its limitations.

Taking a look at the openstd proposal here: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2887.htm We see that the authors are effectively moving to standardise the extant GCC attributes pure and const. This question __attribute__((const)) vs __attribute__((pure)) in GNU C has a few answers which explain their behaviour and differences more thoroughly.

0
On

[[reproducible]] is similar to GCC's pure.

A function is pure if it has no observable effect on the program's state aside from the return value, and if repeated calls in the context of the same program state will return the same value.

A stereotypical pure function is strlen. It does not observably change the program state. And if the entire program state remains the same, including the memory contents pointed at by the pointer argument, it will return the same value.

[[reproducible]] requires a function to be effectless and idempotent, where those terms have specified meaning in the standard. The pure attribute is poorly documented, but the intention seems to be that they agree when all pointer or array types have const qualified target types.

This is different from C++ constexpr, which decorates a function that may be called in a constant expression and thus at the time of translation in a few ways...

First, [[reproducible]] is an assertion about any invocation of the function. constexpr is instead an assertion that some invocation may be possible at translation-time.

Second, constexpr does not require that a constant expression invocation of a constexpr function has no effect (at least since C++14) or that it is idempotent given the state of the program (at least since C++23). Example.

In C++11 (until C++14), constexpr was close to effectless and idempotent. That is because the committee was deliberate in adding permissions to constexpr functions.