Reproduced on 4.6.0 and 4.1.2 as well. Here is the header file: class TestClass { public: void testFn() const; private: static const int VAR1 = 9; static const int VAR2 = 5; }; And here is the source file including it: #include "testclass.h" void TestClass::testFn() const { int b = 1; int c = (b == 0) ? VAR1 : VAR2; int d; if (b == 0) d = VAR1; else d = VAR2; } int main(void) { return 0; } This compiles, but does not link (g++ is called with no options, only the source). The following error is given: gcc-test.o: In function `TestClass::testFn() const': gcc-test.cpp:(.text+0x14): undefined reference to `TestClass::VAR1' gcc-test.cpp:(.text+0x1b): undefined reference to `TestClass::VAR2' collect2: ld returned 1 exit status If I comment out the line "int c = (b == 0) ? VAR1 : VAR2;" in the source, then the linker errors disappear. I have been told that VAR1 and VAR2 are declared and initialized, but not defined, and therefore this code is not valid C++. If it is indeed invalid, then why does only the ternary statement cause a linking error, but not the equivalent if/else?
You need indeed a definition.
Note if case does not need a diagnostic according to the C++ standard.
(In reply to comment #1) > You need indeed a definition. > Why does it require a definition in the ternary case, but not in the if/else?
In the case of if, the value was "inlined" and in the case of ?:, it is not. I had a patch which changed the behavior but lost it when I moved companies.
The result of "(b == 0) ? VAR1 : VAR2" is an lvalue, that's the difference between the two cases.
in this variation the result is not an lvalue, so you can get away without a definition: (b == 0) ? (int)VAR1 : VAR2
(In reply to comment #4) > In the case of if, the value was "inlined" and in the case of ?:, it is not. I > had a patch which changed the behavior but lost it when I moved companies. And what did your patch do exactly?
(In reply to comment #7) > (In reply to comment #4) > > In the case of if, the value was "inlined" and in the case of ?:, it is not. I > > had a patch which changed the behavior but lost it when I moved companies. > > And what did your patch do exactly? It was able to look into xyz?decl1:decl2 and create xyz?ABC:DEF; but I cannot remember where I placed it. It worked for lvalues too because this part was done after (a?b:c) = d; was converted into a?b = d: c = d; or the address expression was pushed into the ?:.
Then, I reopen this as an enhancement request. If you ever find/redo the patch or someone else decides to fix this in the same way, it would a nice improvement for usability.
I disagree that it would be useful, it would encourage non-portable code, and I'd rather be told about the missing definition.
[class.static.data]/3 If a static data member is of const literal type, its declaration in the class definition can specify a brace-or-equal-initializer ... The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer. [basic.def.odr] explains what "used" means. The code is invalid, I don't think it does users a service to accept it.
(In reply to comment #11) > [class.static.data]/3 > If a static data member is of const literal type, its declaration in the class > definition can specify a brace-or-equal-initializer ... The member shall > still be defined in a namespace scope if it is used in the program and > the namespace scope definition shall not contain an initializer. > > [basic.def.odr] explains what "used" means. > > The code is invalid, I don't think it does users a service to accept it. So is g++ accepting invalid code?
(In reply to comment #11) > definition Bah, that entity is the "fi" ligature, it should say definition (In reply to comment #12) > So is g++ accepting invalid code? Yes, but it's a violation of the ODR, no diagnostic is required (it's not possible to tell until link time that there's no definition.) There are DOZENS of duplicates of this bug, they are all invalid.
> (In reply to comment #12) > > So is g++ accepting invalid code? > > Yes, but it's a violation of the ODR, no diagnostic is required (it's not > possible to tell until link time that there's no definition.) > > There are DOZENS of duplicates of this bug, they are all invalid. However, it links in the if-else case. I understand that ?: may be used as a lvalue, but in this case, it is not and the value may be inlined in the same way as in if-else (I guess that is what Andrew's patch did). If the standard is clear that this should not work, then so be it. Let's close this as INVALID, because I don't know how we could improve the diagnostics here to help users. I wish we could but I cannot see how it can be done. I guess that would require an integrated super-smart linker, I wonder if the LLVM project is going to suggest that next?
(In reply to comment #14) > > However, it links in the if-else case. The variable is not "used" in the [basic.def.odr] sense, because the lvalue-to-rvalue conversion occurs immediately. > I understand that ?: may be used as a > lvalue, but in this case, it is not and the value may be inlined in the same > way as in if-else (I guess that is what Andrew's patch did). If the standard is > clear that this should not work, then so be it. The lvalue-to-rvalue conversion doesn't happen immediately to either the second or third operand, it happens to the result of the conditional expression. Andrew's idea might be allowed by the as-if rule, but I'm not sure. It must not change the behaviour of valid programs. And in any case, the original example is invalid. Supporting it is not important IMHO. > Let's close this as INVALID, because I don't know how we could improve the > diagnostics here to help users. I wish we could but I cannot see how it can be > done. I guess that would require an integrated super-smart linker, I wonder if > the LLVM project is going to suggest that next? closing again
*** Bug 45825 has been marked as a duplicate of this bug. ***
*** Bug 52455 has been marked as a duplicate of this bug. ***