首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >未命名类C++中的静态数据成员

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

Stack Overflow用户
提问于 2016-01-07 07:01:58
回答 3查看 3.4K关注 0票数 7

我在下面的链接中看到,未命名(匿名)类不应该包含静态数据备忘录。谁能让我知道原因吗?

2.1.0/com.ibm.zos.v2r1.cbclx01/cplr038.htm说..。

程序中只能有一个静态成员的定义。未命名类、未命名类中包含的类和本地类不能具有静态数据成员。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-01-07 07:08:51

如果使用ODR,所有static成员数据都必须在类/结构之外定义。

代码语言:javascript
复制
struct Foo
{
    static int d;
};

int Foo::d = 0;

如果类/结构未命名,则无法定义类外部的成员。

代码语言:javascript
复制
int ::d = 0;

不能用于定义未命名类的静态成员。

更新C++17

如果您能够使用C++17或更新版本,则可以使用

代码语言:javascript
复制
static inline int d = 10;

这将允许在匿名的static /struct中定义一个class成员变量。

示例代码以演示不需要在类定义之外定义static成员变量:

代码语言:javascript
复制
#include <iostream>
struct foo
{
    static inline int d = 10;
};

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

命令建造:

代码语言:javascript
复制
g++ -std=c++17 -Wall    socc.cc   -o socc

运行程序的输出:

代码语言:javascript
复制
10

感谢@Jean-Micha lCelerier对更新的建议。

票数 13
EN

Stack Overflow用户

发布于 2016-01-07 07:27:41

你确定标准真的禁止这样做吗?

如前所述,当您需要对静态成员进行实际定义时,就会出现这个问题。该语言没有提供任何方法来定义它。引用它没有其他问题,因为我们可以在struct内部或通过它的一个实例进行引用。

但以GCC为例,他会接受以下几点:

代码语言:javascript
复制
static struct {
    static int j;
} a;

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

但是它不能链接,因为a.j指的是一个未定义的符号(._0::j),但是有一种方法可以绕过这个问题。通过在汇编程序中定义它,或者通过使用编译器扩展,您可以。例如,添加行

代码语言:javascript
复制
int j asm("_ZN3._01jE") = 42;

会让它发挥作用的。在这种情况下,_ZN3._01jE是静态变量的真正损坏名称,无论是损坏还是未损坏的名称都不能直接用作标准C++中的标识符(但可以通过GCC扩展或汇编程序)。

您可能必须意识到,这将只适用于特定的编译器。其他编译器会以其他方式破坏这个名称(甚至会做其他的事情,使得这个技巧根本行不通)。

你真的应该问为什么你想用这个把戏。如果您可以使用标准方法来完成这项工作,那么您很可能应该选择这样做。例如,您可以使用匿名namespace来降低可见性,例如:

代码语言:javascript
复制
namespace {
    static struct Fubar {
         static int j;
    } a;

    Fubar::a = 0;
}

现在Fubar并不是真正的匿名的,但它至少将被限制在翻译单元。

票数 1
EN

Stack Overflow用户

发布于 2021-06-01 19:35:11

当C++标准化时,未命名的类不能具有静态数据成员,因为无法定义/实例化它们。但是,C++11已经解决了这个问题,因为它添加了decltype操作符:

代码语言:javascript
复制
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 
}

因此,原则上,可能存在带有静态数据成员的未命名类或结构。但是,C++标准制定者故意不允许这种语法,因为编译器不知道,它应该给这个decltype(a)::j命名链接。所以大部分(全部?)编译器--包括正常模式下GCC的当前版本--拒绝编译。

-fpermissive模式下,GCC-9和GCC-10接受这段代码并很好地编译它.但是,如果a的声明被移动到一个头文件中,这个头文件包含在不同的源文件中,那么它们在链接阶段仍然会失败。

因此,未命名的类只能在单个翻译单元中使用。为了避免污染全局名称空间,只需在匿名名称空间中放置任何需要保持本地的内容。所以:

代码语言:javascript
复制
namespace {
    struct whatever {
        static int j;
    } a;
    int whatever::j = 42;
}
int main() {
    return a.j == 42 ? 0 : 1; 
}

如果名称whatever与另一个头文件中的名称冲突,则编译良好,不会污染全局命名空间,甚至不会导致问题。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34649138

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档