Continued "I just can't understand DR 712"

This is basically a continuation of my previous question about DR 712. Let me first explain why I insist on looking at what can be considered old, since the C ++ 11 standard, but my problem is that the [basic. def.odr] is already hard to understand in C ++ 11, and I want to cover it completely before moving on to the same section in the current project, which, in my opinion, is even more complicated.

The answer to my previous Austing Hasting question was great, but I still have one small point that is not clear in [basic.def.odr] / 2 in C ++ 11. Consider this small and very simple example:

const int i = 1; int main() { int j = i; } 

From [basic.def.odr] / 2 in C ++ 11 i not odr-used in int j = i; since i is an object that satisfies the requirement of appearing in a constant expression and the lvalue-to-rvalue transform is immediately applied to i . This doesn't really matter to me, since i is clealy used in the declaration int j = i; as seen from the slightly modified code shown here , where I made the variable i not optimize from compiled code.

Of course, there should be something wrong with my reasoning, because I do not believe that C ++ 11 could be wrong with such a simple example. Again, what am I missing now?

+5
source share
1 answer

I am trying to translate my understanding of the standard "used" and "one definition rule" into something more intuitive. Terms other than “used” and “ODR-used” are not standard terms below.


Something used by ODR basically means "we need him to have a personality." This usually means that someone accepts a link or a pointer to it.

If you only need the cost of something, this does not always make it ODR-usable. The value of the compile-time constant does not require identification.

In C ++, identity basically means "in fact, it should take place somewhere."

The standard does not say “ODR is used if we need it to have an identifier”, because then different compilers will have different rules to determine if they need identification. As an example, if an operation was built in and the link is gone, does this mean that it no longer needs an identifier?

Thus, the standard describes what ODR is used and distinguishes it from the value used.

 int j = i; 

this does not require the identity i . He just needs his value. const int i = 1; matters, which cannnot (with certain behavior) changes.

 int const* pj = &i; 

this requires identification. Two different pointers to i must agree on the location of i according to the standard.

 void foo( const int& x ) { int j = x; } foo(i); 

This also requires an identifier for i . We turn to i . Although the only thing we do is just a reference to its value, the (short, theoretical) existence of this link means that it has an identity.

 const int a = 3; const int b = 4; int i = (a<2)?a:b; 

the defect was that this required a and b have an identifier (they used ODR), because the interaction ? with the rules used. The defect said: "We must fix it."

Link to DR 712

And after this resolution, this expression only needs the values ​​of a and b , and not their identifiers, so they do not need to store it.

We care if something has memory, because things that need to be stored must have a unique definition point. They cannot exist solely in the header file, basically.

Note that with built-in variables in C ++ 17 this may be less; in accordance with the as-if rule, the created built-in storage location can be erased from existence if no one pays attention to the person. Since functions that take const& can "accidentally" force the application of identity requirements to things designed to mean only values, this is a nice relaxation of the rules.

+9
source

Source: https://habr.com/ru/post/1264889/


All Articles