The program clearly violates one rule of definition, as you stated in your question. But in this case, the standard does not require diagnostics. This is explicit from 3.2. One definition rule [basic.def.odr] Β§4 (emphasis)
Each program must contain exactly one definition of each non-line font or variable that is used as odr in this program; no diagnostics required .
and 1.4 Execution of the execution of [intro.compliance] Β§2.3 says:
If a program contains a violation of a rule for which no diagnostics are required, this International Standard does not require any implementation requirements for this program.
This means that gcc is right to strangle this program because one rule has been violated. But this is not a mistake when MSVC accepts it as a compiler extension (*) without warning, because the standard does not require any requirements here.
We are in undefined compilation time, called a poorly formed program that does not require diagnostics. A compiler implementation can do anything:
- reject program
- automatically fix the error and generate the code as if the definition were (for the current case)
- remove the offensive line [s] if that makes sense and compiles the program - even if what is being generated does not match the expected programmer
- compile it into a program that ends with a runtime error
- [add everything you think, but I never saw the compiler hit my cat ...]
(*) more precisely, this is a compiler extension, if documented. Unfortunately, at the moment I do not have complete documentation for the MSVC compiler, so I canβt say whether it is documented and is a compatible extension or not, and this is just ... one possible program execution
Below is a small version of the OP code, demonstrating that the compiler provided a definition:
#include <iostream> class AE { // ... public: static const int c6 = 7; static const int c7 = 31; }; const int AE::c7; // definition int main() { const int* p1 = &AE::c6; // error: c6 not an lvalue const int* p2 = &AE::c7; // ok // ... std::cout << *p1 << "(" << p1 << ") - " << *p2 << "(" << p2 << ")" << std::endl; return 0; }
Exit (with old MSVC 2008, debug mode to avoid as much optimization as possible):
7(00DF7800) - 31(00DF7804)
i.e. expected values ββand sequential addresses
With the same code, Clang 3.4 complains (as expected) about link time with
undefined reference to `AE::c6'