Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static data member in an unnamed class C++

Tags:

c++

I read in the below link that unnamed(anonymous) class should not have static data memebers in it. Could anyone please let me know the reason for it?

https://www-01.ibm.com/support/knowledgecenter/SSLTBW_2.1.0/com.ibm.zos.v2r1.cbclx01/cplr038.htm says the below..

You can only have one definition of a static member in a program. Unnamed classes, classes contained within unnamed classes, and local classes cannot have static data members.

like image 603
Srikanth Avatar asked Jan 07 '16 07:01

Srikanth


People also ask

What is static data member in C?

When a data member is declared as static , only one copy of the data is maintained for all objects of the class. Static data members are not part of objects of a given class type. As a result, the declaration of a static data member is not considered a definition.

What is static class member in C?

A static member has certain special characteristics. These are: Only one copy of that member is created for the entire class and is shared by all the objects of that class, no matter how many objects are created. It is initialized before any object of this class is being created, even before main starts.

How do you initialize a static data member of a class?

Static Data Member Initialization in C++ We can put static members (Functions or Variables) in C++ classes. For the static variables, we have to initialize them after defining the class. To initialize we have to use the class name then scope resolution operator, then the variable name.

Why static members are defined outside the class?

Because static member variables are not part of the individual class objects (they are treated similarly to global variables, and get initialized when the program starts), you must explicitly define the static member outside of the class, in the global scope.


3 Answers

All static member data, if they are ODR-used, must be defined outside the class/struct.

struct Foo
{
    static int d;
};

int Foo::d = 0;

If the class/struct is unnamed, there is no way to define the member outside the class.

int ::d = 0;

cannot be used to define the static member of an unnamed class.

Update for C++17

If you are able to use C++17 or newer, you may use

static inline int d = 10;

That will allow a static member variable to be defined in an anonymous class/struct.

Sample code to demonstrate that a static member variable need not be defined outside the class definition:

#include <iostream>
struct foo
{
    static inline int d = 10;
};

int main()
{
   auto ptr = &foo::d;
   std::cout << *ptr << std::endl;
}

Command to build:

g++ -std=c++17 -Wall    socc.cc   -o socc

Output of running the program:

10

Thanks are due to @Jean-MichaëlCelerier for the suggestion for the update.

like image 137
R Sahu Avatar answered Oct 03 '22 04:10

R Sahu


Are you sure that the standard actually forbids this?

As mentioned the problem arises as you need to have an actual definition of the static member. The language provides for no method to define it. There is no other problems in referring to it as we can do it from within the struct or via an instance of it.

However GCC for example will accept the following:

static struct {
    static int j;
} a;

int main() {
    return a.j; // Here we actually refers to the static variable
}

but it can't be linked as a.j refers to an undefined symbol (._0::j), but there's a way to get around this. By defining it in assembler or by using compiler extensions you could. For example adding the line

int j asm("_ZN3._01jE") = 42;

Will make it work. _ZN3._01jE is the real mangled name of the static variable in this case, neither the mangled or unmangled name can be used directly as a identifier in standard C++ (but it can via GCC extension or assembler).

As you must probably realize this would only work with specific compilers. Other compilers would mangle the name in other ways (or even do other things that may make the trick not work at all).

You should really question why you would like to use this trick. If you can do the work using standard methods you should most probably chose that. For example you could reduce the visibility by using anonymous namespace instead for example:

namespace {
    static struct Fubar {
         static int j;
    } a;

    Fubar::a = 0;
}

Now Fubar is not really anonymous, but it will at least be confined to the translation unit.

like image 25
skyking Avatar answered Oct 03 '22 03:10

skyking


When C++ was standardized, unnamed classes could not have static data members, as there was no way to define/instantiate them. However, this problem has been solved with C++11, as it added the decltype operator:

struct {
    static int j;
} a;

// Declare the static member of the unnamed struct:
int decltype(a)::j = 42;

int main() {
    return a.j == 42 ? 0 : 1; // Use the static member 
}

So, in principle, there could be unnamed classes or structs with static data members. But the C++ standard makers deliberately did not allow this syntax, as the compiler doesn't know, which name it should give to that decltype(a)::j thing for linking. So most (all?) compilers - including current versions of GCC in normal mode - refuse to compile this.

In -fpermissive mode, GCC-9 und GCC-10 accept this code and compile it fine. However, if the declaration of a is moved to a header file, that is included from different source files, they still fail at the linking stage.

So unnamed classes can only be used inside a single translation unit. To avoid polluting the global namespace, just put anything, that needs to stay local, inside an anonymous namespace. So:

namespace {
    struct whatever {
        static int j;
    } a;
    int whatever::j = 42;
}
int main() {
    return a.j == 42 ? 0 : 1; 
}

compiles fine, doesn't pollute global namespace, and even doesn't lead to problems, if the name whatever clashes with a name from another header file.

like image 42
Kai Petzke Avatar answered Oct 03 '22 05:10

Kai Petzke