1

I seem to have some misconceptions about how the static keyword works in C++; specifically, I need to understand the problem with the following code:

#include <iostream>

struct A{
    int a;

    A(int ain) : a(ain) { }
    A() : a(1) { }

    static A getA()
    {
        return A(2);
    }
};

struct B
{
    static A a = A::getA();
};


int main() {
    std::cout << B::a.a << std::endl;
}

Had static worked as I expected it to, the above code sample would have printed 2 and exited normally - instead, I get the following compiler error message:

g++    -c -o syntax.o syntax.cpp
syntax.cpp:17:21: error: ‘A::getA()’ cannot appear in a constant-expression
     static A a = A::getA();
                     ^
syntax.cpp:17:26: error: a function call cannot appear in a constant-expression
     static A a = A::getA();
                          ^
syntax.cpp:17:26: error: invalid in-class initialization of static data member of non-integral type ‘A’
syntax.cpp:17:26: error: initializer invalid for static member with constructor
syntax.cpp:17:26: error: (an out of class initialization is required)
syntax.cpp:17:26: error: ‘B::a’ cannot be initialized by a non-constant expression when being declared
make: *** [syntax.o] Error 1

I read the error messages and I realize that there's something about static that I haven't understood, but I find it hard to pinpoint what. It's probably because I've done a fair amount of work in languages like Java and C#, which also have the static keyword but where it, apparently, works differently.

Will someone please explain to me why the above code is invalid?

Tomas Aschan
  • 58,548
  • 56
  • 243
  • 402
  • For starters, B has no `getA()` method. The line `std::cout << B.getA().a << std::endl;` can never compile. Secondly, `A.getA();` should be `A::getA();`. – executifs Mar 24 '14 at 09:11
  • @executifs: Sorry, it seems I was a little too eager to provide something runnable to note the problems in my main method. I've updated to something more reasonable now. – Tomas Aschan Mar 24 '14 at 09:24
  • And yet it still has the same errors.... – mjs Mar 24 '14 at 09:28
  • 1
    @mjs: There. Now I also updated the compiler error message to what it currently gives me. – Tomas Aschan Mar 24 '14 at 09:29

3 Answers3

4

STATIC MEMBER FUNCTIONS

There are two ways of invoking a static member function of a given T, either;

  • you use the scope resolution operator ::, or;

  • you invoke it on an instance of said type T using operator. (as if you were invoking any other member-function on the variable).


LEGAL CONSTRUCTS

struct Obj {
  static void func () { 
    /* ... */
  }
};

The two snippets below both call the static member function func within Obj.

Obj a; a.func ();

Obj::func ();


ILLEGAL CONSTRUCTS

Obj a;

Obj.func (); // illegal, `Obj` is a type and not an instance
a ::func ();  // illegal, `a` is an instance of `Obj`, not a type


STATIC DATA MEMBERS

static data members are used to declare a variables that are shared between every instance of a given type.

In the snippet provided in the question you are trying to initialize a static data member a of type A with the returned value from, the corrected, A::getA (). This is not allowed since trying to initialize a static data member without making it constexpr is an illegal construct for in-class initialization.

struct B {
  static A a = A::getA(); // illegal, `static A a` is not `constexpr`
};

More about in-class initialization of static data members can be found here:

Community
  • 1
  • 1
Filip Roséen - refp
  • 62,493
  • 20
  • 150
  • 196
  • Thanks - I apparently needed pointers both about accessing static members and about static data member initialization. In the end, I wanted to keep declaration and definition together, and changed `B` to `struct B { static A a() { return A::getA(); } }`. This doesn't really make sense in my example, but that just shows that my example is a simplification. Thanks again! – Tomas Aschan Mar 24 '14 at 09:56
3

There are two issues. First, the syntax A.getA() is wrong: the . syntax is for accessing the members of an instance. You cannot use it to access members via a type. To use the . operator, you would have to create an instance of A, and call getA() via that instance. But that wouldn't make any sense. So what you need to do is call the method using the class scope resolution, i.e. A::getA(). That is the first problem.

The second is that you cannot define a non-const, non-integral static member at the point of declaration. You have to separate declaration from definition. The latter should be in one translation unit only, which means putting it in a single .cpp file:

Header file:

struct B
{
    static A a; // declaration
};

Implementation file

A B::a = A::getA(); // definition
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
1

Your are using the syntax to call a instance function, you need to use the scope resolution operator :: syntax instead:

A::getA();
Stormenet
  • 25,926
  • 9
  • 53
  • 65