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

3

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

5 Comments

@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.
Well, hopefully, the OP has a choice. Even MSVC seems to have it, see here.
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 :)
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.
s/should/must/, I think!
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.

4 Comments

I believe this change to constexpr is only for static class members, but don't quote me on that either.
@Quentin constexpr inline int array[] = { 11, 12, 13, 14, 15 }; compiles outside a class, see here. I really like this new compiler feature.
I miswrote. I mean that constexpr variables being implicitly inline applies to class members, constexpr globals are still implicitly static AFAIK.
@Quentin Oh right, could be, I misread. OP then please be advised to include the inline keyword I recommended anyway.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.