4

I have a strange gcc 4.7 problem with c++11 enabled :

When I want to compile this:

constexpr unsigned int getDim(const int e){
        return (e==1)?  A::Set::Dimension :
            (
              (e==2)? B::Set::Dimension :

                (
                    (e==3)? C::Set::Dimension :
                    (
                       +D::Set::Dimension

                    )
                )
            );
 }

where for each struct A,B,C,D a typedef for Set is defined where the related Set has an int Dimension, for example

struct SetOne{
   static const int Dimension = 1;
}

struct A{
   typedef SetOne Set;
}

If I don't use the unary + infront of D::Set::Dimension the linker fails complaining about undefined references to SetOne::Dimension.

Is this the same problem as: Undefined reference to static class member

I cannot give a MWE as the problem vanished for a simple example with one .cpp file. ? (but all definitions are for A,B,C,D are in one header file)

Does anybody have a clue what might go wrong here? This is unintuitiv :-)

Observation 2: If one replaces: +D::Set::Dimension with 0, it compiles fine, but why the hack the other statements as A::Set::Dimension do not rise the same linking error?

Community
  • 1
  • 1
Gabriel
  • 8,990
  • 6
  • 57
  • 101
  • 1
    Yes, your assumption about previously answered question seems to be true. `static const int Dimension = 1;` inside class declaration is only a static variable declaration, not definition (despite initialization). You should explicitly define static members of a class outside its declaration. – Constructor Mar 10 '14 at 18:38
  • If I define the static members outside of the class decleration in a cpp file then I cannot use the static int in a template function ``f`` as the compiler needs to see the const expression ...? How can I avoid this? – Gabriel Mar 10 '14 at 19:12
  • 1
    If you are using for such purposes only static variables of integral type, you may initialize them inside your class and create their definitions outside of the class **without** any initialization. **Initialization is not the same as definition.** If you can use C++11 you may also try to use `constexpr` keyword. – Constructor Mar 10 '14 at 19:42

1 Answers1

8

In the expression you are building, the ternary expression is yielding an lvalue, which causes the odr-use of the static constant. The One Definition Rule requires that all static members that are odr-used are defined, so you need to provide a definition (in a single translation unit).

So why does the problem go away with the unary +?

The unary + does not cause the odr-use of the static member, it only requires an rvalue, and the result of it is another rvalue. That cascades out through the conditional operators as once one of the two arguments is an rvalue the result of the expression will also be an rvalue. The end result is that the single + has the effect of forcing the lvalue-to-rvalue conversion of all of the static consts used in the function and removes the odr-uses.

If one replaces: +D::Set::Dimension with 0, it compiles fine

Again, 0 is an rvalue, and it will have the same effect as the unary + described above.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489