I have the following code in a header file, that is included in 2 different cpp files:
constexpr int array[] = { 11, 12, 13, 14, 15 };
inline const int* find(int id)
{
auto it = std::find(std::begin(array), std::end(array), id);
return it != std::end(array) ? &*it : nullptr;
}
I then call find(13)
in each of the cpp files. Will both pointers returned by find()
point to the same address in memory?
The reason I ask is because I have similar code in my project and sometimes it works and sometimes it doesn't. I assumed both pointers would point to the same location, but I don't really have a basis for that assumption :)
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 .
Since C++17 std::array can be declared as constexpr: constexpr std::array myArray{1, 2, 3}. Now starts the fun part. With C++20, you can use a std::array at compile-time. The std::array (1) and all results of the calculations are declared as constexpr .
A constexpr specifier used in an object declaration or non-static member function (until C++14) implies const . A constexpr specifier used in a function or static data member (since C++17) declaration implies inline .
constexpr implies const and const on global/namespace scope implies static (internal linkage), which means that every translation unit including this header gets its own copy of PI.
In C++11 and C++14:
In your example array
has internal linkage (see [basic.link]/3.2), which means it will have different addresses in different translation units.
And so it's an ODR violation to include and call find
in different translation units (since its definition is different).
A simple solution is to declare it extern
.
In C++17:
[basic.link]/3.2 has changed such that constexpr
can be inline
in which case there will be no effect on the linkage anymore.
Which means that if you declare array
inline
it'll have external linkage and will have the same address across translation units. Of course like with any inline
, it must have identical definition in all translation units.
I can't claim to be an expert in this, but according to this blog post, the code you have there should do what you want in C++17, because constexpr
then implies inline
and that page says (and I believe it):
A variable declared inline has the same semantics as a function declared inline: it can be defined, identically, in multiple translation units, must be defined in every translation unit in which it is used, and the behavior of the program is as if there was exactly one variable.
So, two things to do:
array
as constexpr inline
to force a compiler error on older compilers (and to ensure that you actually get the semantics you want - see comments below)I believe that will do it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With