Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

constexpr global constants in a header file and odr

Tags:

Unfortunately, I am somewhat confused about constexpr, global constants declared in header files, and the odr.

In short: Can we conclude from here

https://isocpp.org/files/papers/n4147.pdf

that

constexpr MyClass const MyClassObj () { return MyClass {}; } constexpr char const * Hello () { return "Hello"; } 

is preferable over

constexpr MyClass const kMyClassObj = MyClass {}; constexpr char const * kHello = "Hello"; 

for defining globals in a header file if I want to "just use" those globally declared/defined entities and do not want to think about how I use them?

like image 643
JohnB Avatar asked Dec 23 '15 23:12

JohnB


People also ask

Should constexpr be in header?

In other words, you should use constexpr for your constants in header files, if possible, otherwise const . And if you require the address of that constant to be the same everywhere mark it as inline .

What does constexpr const mean?

constexpr creates a compile-time constant; const simply means that value cannot be changed.

Is constexpr constant?

The keyword constexpr was introduced in C++11 and improved in C++14. It means constant expression. Like const , it can be applied to variables: A compiler error is raised when any code attempts to modify the value. Unlike const , constexpr can also be applied to functions and class constructors.


1 Answers

Note: as of C++17, you can declare your variables as inline.


TL;DR: If you want to be on the (very) safe side, go with constexpr functions. It isn't inherently necessary though, and certainly won't be if you're performing trivial operations on these objects and are solely interested in their value, or simply don't use them in the dangerous scenarios listed below.

The fundamental issue is that const variables at namespace scope such as yours (generally) have internal linkage ([basic.link]/(3.2)). This implies that each translation unit compiling the corresponding header will observe a different entity (i.e. symbol).

Now imagine we have a template or inline function in a header using those objects. The ODR is very precise about this scenario - [basic.def.odr]/6:

enter image description here

"initialized with a constant expression" is certainly met, since we're talking constexpr. So is "the object has the same value in all definitions of D" if you don't monkey about.

"the object isn't odr-used" is probably the only questionable condition. Basically, it requires that you don't necessitate the variables runtime existence as a symbol, which in turn implies that

  • You don't bind it to a reference (=> you don't forward it!)

  • You don't (neither explicitly nor implicitly) take its address.

The only exception to the second rule are arrays, which can be taken the address of implicitly inside a subscript operation as long as the two above rules aren't violated for the yielded glvalue.

More precisely, odr-use is governed by [basic.def.odr]/3:

A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.20) that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression (Clause 5).

Applying l-t-r to any constexpr variable will behave as required by the first part. The second part requires that the variable be used as a value rather than an actual object; that is, it's eventually either discarded or directly evaluated, giving the above rules of thumb.

If you avoid odr-use of the variable inside inline functions, templates or the like, you're fine. But if you use the return value of a corresponding constexpr function, you won't have to worry, since prvalues are already behaving more like values/literals (not objects) and constexpr functions are inline and definitely won't violate the ODR (if you don't use constexpr variables inside there!).

like image 118
Columbo Avatar answered Sep 22 '22 14:09

Columbo