Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

constexpr and ODR

If we have a header file widget.hpp with the contents below:

constexpr int foo = 10;

struct widget
{
    int bars[foo];
};

...and we have two translation units generated from two source files which both only include widget.hpp, does this violate the one definition rule (more specifically, does the use of foo violate the one definition rule)?

foo has internal linkage but it is also a constant expression. From my reading of 3.2.6 in the C++11 standard, which I will quote below, this is well-formed if requirement #2 is not referring solely to static data members.


3.2.6 requirement #2:

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 (13.3) and after matching of partial template specialization (14.8.3), 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 (5.19), and the object is not odr-used, and the object has the same value in all definitions of D

like image 790
Simple Avatar asked Jun 17 '13 00:06

Simple


1 Answers

The only place I can see any room for question about your case would be whether or not your use of foo qualifies as odr-used or not. Perhaps the easiest way to clarify at least the intent would be to quote the corresponding section of n1337 (immediately followed the official standard, mostly cleaning up some phrasing, such as in this case):

[...] a name can refer to a 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 (5.19), and the value (but not the address) of the object is used, and the object has the same value in all definitions of D;

Your use clearly meets all these requirements.

  1. foo has type int in every case.
  2. foo is initialized with a constant expression.
  3. you use only the value, not the address, of foo.
  4. foo has the same value in all defintions of widget.

That said, you'd probably be better off changing foos to a std::vector instead:

struct widget { 
    std::vector<int> bars;

    widget : bars(foo) {}
};
like image 144
Jerry Coffin Avatar answered Sep 29 '22 05:09

Jerry Coffin