3

Looking at another question I realized that I can't use objects or functions from an anonymous namespace through a header file since it'll cause ODR violations in class definitions or inline functions. If this is the case, then is it possible to use named const or constexpr static objects in inline functions or in classes safely? For example, if CONSTANT was inside of namespace below it would be unsafe, but is it okay to use a constant with static linkage?

// some header file to be included by multiple .cpp files
static const/*expr*/ int CONSTANT = 2;

inline int f() {
  return CONSTANT;
}

class Cls {
  int mem = CONSTANT;
};
Community
  • 1
  • 1
Ryan Haining
  • 35,360
  • 15
  • 114
  • 174
  • 1
    At least in C++17 this is no longer an issue. Oddly, a type alias could solve your problems: `using CONSTANT = std::integral_constant;` – Barry Dec 14 '16 at 01:44
  • @Barry the "the object is not odr-used" from M.M's quote removed for C++17 I gather? – Ryan Haining Dec 14 '16 at 01:48
  • N4606 (which is the latest standard draft according to isocpp.org) still has "the object is not odr-used" – M.M Dec 14 '16 at 01:49
  • Naw, now you can just do `static constexpr inline CONSTANT = 2;` – Barry Dec 14 '16 at 01:50
  • @Barry Can you provide a reference? And did you mean `static constexpr inline int CONSTANT = 2;` – M.M Dec 14 '16 at 01:51
  • @M.M http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0386r0.pdf – Ryan Haining Dec 14 '16 at 01:53
  • stroustrup was not happy about it iirc – Ryan Haining Dec 14 '16 at 01:56
  • @RyanHaining according to that document "A function or variable declared with the constexpr specifier is implicitly an inline function or variable", so `inline` would be redundant. Also I don't see where the changes in that document would make the code no longer be an ODR violation. – M.M Dec 14 '16 at 01:59
  • 1
    @M.M sorry idk why I thought it would at first.. waiting for Barry's response – Ryan Haining Dec 14 '16 at 02:02
  • @M.M. Don't know the exact details as to which terms you can omit. Can't hurt to add all three. And yeah, missed the `int` – Barry Dec 14 '16 at 03:26
  • 1
    @RyanHaining N4606 is dated after that document, and some of the text differs between that document and N4606 so we need to be careful – M.M Dec 14 '16 at 07:52
  • @Barry `static inline` doesn't make any sense. Just plain `inline`. And then, since it has external linkage, all uses of the name would refer to the same variable. – T.C. Dec 14 '16 at 08:43

1 Answers1

5

This code is OK. The full paragraph (C++14 [basic.def.odr/6.2]) is:

in each definition of D, corresponding names, looked up according to 3.4, shall refer to an entity defined within the definition of D, or shall refer to the same entity, after overload resolution and after matching of partial template specialization, except that a name can refer to a non-volatile const object with internal or no linkage if the object has the same literal type in all definitions of D, and the object is initialized with a constant expression, and the object is not odr-used, and the object has the same value in all definitions of D; and

This usage does match all of the conditions in the "except ... and ... and ..." part:

  • The name CONSTANT does in fact refer to a non-volatile const object with internal linkage
  • It has the same literal type in all definitions of f().
  • It is initialized with a constant expression 2.
  • It is not odr-used.
  • It has the same value in all definitions of f().

The point "It is not odr-used" is supposed to mean "It is not odr-used within f()" -- i.e. it doesn't break f() if you happen to odr-use CONSTANT elsewhere in the program.

M.M
  • 138,810
  • 21
  • 208
  • 365