简体   繁体   English

未命名类 C++ 中的静态数据成员

[英]Static data member in an unnamed class 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.. https://www-01.ibm.com/support/knowledgecenter/SSLTBW_2.1.0/com.ibm.zos.v2r1.cbclx01/cplr038.htm在下面说..

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.未命名类、未命名类中包含的类和本地类不能具有静态数据成员。

All static member data, if they are ODR-used, must be defined outside the class/struct.所有static成员数据,如果它们被 ODR 使用,必须在类/结构之外定义。

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 C++17 更新

If you are able to use C++17 or newer, you may use如果您能够使用 C++17 或更高版本,则可以使用

static inline int d = 10;

That will allow a static member variable to be defined in an anonymous class / struct .这将允许在匿名class / struct定义static成员变量。

Sample code to demonstrate that a static member variable need not be defined outside the class definition:演示static成员变量不需要在类定义之外定义的示例代码:

#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.感谢@Jean-MichaëlCelerier 提出更新建议。

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.引用它没有其他问题,因为我们可以从struct或通过它的实例来完成。

However GCC for example will accept the following:但是,例如 GCC 将接受以下内容:

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 aj refers to an undefined symbol ( ._0::j ), but there's a way to get around this.但它不能被链接,因为aj指的是一个未定义的符号( ._0::j ),但有一种方法可以解决这个问题。 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).在这种情况下, _ZN3._01jE是静态变量的真实_ZN3._01jE名称, _ZN3._01jE_ZN3._01jE名称还是未重整名称都不能直接用作标准 C++ 中的标识符(但它可以通过 GCC 扩展或汇编程序)。

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来降低可见性,例如:

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.现在Fubar并不是真正的匿名,但它至少会被限制在翻译部门。

When C++ was standardized, unnamed classes could not have static data members, as there was no way to define/instantiate them.当 C++ 被标准化时,未命名的类不能有静态数据成员,因为无法定义/实例化它们。 However, this problem has been solved with C++11, as it added the decltype operator:但是,这个问题已经在 C++11 中解决了,因为它添加了decltype操作符:

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.但是 C++ 标准制定者故意不允许这种语法,因为编译器不知道它应该给那个decltype(a)::j东西赋予哪个名称以进行链接。 So most (all?) compilers - including current versions of GCC in normal mode - refuse to compile this.所以大多数(全部?)编译器——包括当前版本的正常模式下的 GCC——拒绝编译它。

In -fpermissive mode, GCC-9 und GCC-10 accept this code and compile it fine.-fpermissive模式下,GCC-9 和 GCC-10 接受此代码并正常编译。 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.然而,如果声明a移动到一个头文件,是从不同的源文件包括在内,他们仍然无法在链接阶段。

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.编译好,不污染全局命名空间,如果名称甚至不会导致问题, whatever从另一头文件的名称冲突。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM