7

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 :)

rozina
  • 4,120
  • 27
  • 49
  • Possible duplicate of [C++ standard: do namespace-scoped constexpr variables have internal linkage?](https://stackoverflow.com/questions/46107312/c-standard-do-namespace-scoped-constexpr-variables-have-internal-linkage) – drRobertz Jun 04 '18 at 11:21
  • @drRobertz Not always, anymore... – Paul Sanders Jun 04 '18 at 13:10
  • The question is still a duplicate (tagged c++17 and c++11), so answer the other one too ;-) – drRobertz Jun 04 '18 at 16:09

2 Answers2

9

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.

rustyx
  • 80,671
  • 25
  • 200
  • 267
  • @PaulSanders - it's unclear if the OP is asking about C++11 or C++17. Based on the fact that it "doesn't work" I assume C++11. But added the bit about C++17. – rustyx Jun 04 '18 at 12:31
  • Well, hopefully, the OP has a choice. Even MSVC seems to have it, see [here](https://blogs.msdn.microsoft.com/vcblog/2017/12/19/c17-progress-in-vs-2017-15-5-and-15-6/). – Paul Sanders Jun 04 '18 at 12:59
  • I was compiling as C++14, but in recent Android Studio updates C++17 became available, so I changed it to 17 and it now works. Thanks for the explanation to why it didn't work and why it now works :) – rozina Jun 04 '18 at 13:04
  • Btw your link about implicit inline states that only functions and static data members are implicitly inline. In case of my array it has to be `inline constexpr`. – rozina Jun 04 '18 at 13:07
  • s/should/must/, I think! – Toby Speight Jun 04 '18 at 13:34
3

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:

  • make sure you are compiling as C++17
  • declare 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.

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
  • 1
    I believe this change to `constexpr` is only for `static` class members, but don't quote me on that either. – Quentin Jun 04 '18 at 11:56
  • @Quentin `constexpr inline int array[] = { 11, 12, 13, 14, 15 };` compiles outside a class, see [here](https://wandbox.org/permlink/uEyNKsdw54AUcX4B). I really like this new compiler feature. – Paul Sanders Jun 04 '18 at 12:56
  • I miswrote. I mean that `constexpr` variables being implicitly inline applies to class members, `constexpr` globals are still implicitly `static` AFAIK. – Quentin Jun 04 '18 at 13:03
  • @Quentin Oh right, could be, I misread. OP then please be advised to include the `inline` keyword I recommended anyway. – Paul Sanders Jun 04 '18 at 13:07