为什么我不能在类中初始化`const const std :: string`一个静态成员

luk*_*k32 8 c++ in-class-initialization c++11

我有以下工作代码:

#include <string>
#include <iostream>

class A {
public:
  const std::string test = "42";
  //static const std::string test = "42"; // fails
};

int main(void){
  A a;
  std::cout << a.test << '\n';
}
Run Code Online (Sandbox Code Playgroud)

是否有充分理由不能进行测试static const?我确实在c ++ 11之前理解它受到标准的限制.我认为c ++ 11引入了类内初始化,使其更友好一些.很长一段时间以来,我也没有这种语义可用于整数类型.

当然它适用于以类的形式进行的类外初始化 const std::string A::test = "42";

我想,如果你能把它变成非静态的,那么问题在于其中一个.初始化它的类外范围(通常const是在对象实例化期间创建的).但是,如果您创建一个独立于该类的任何其他成员的对象,我认为这不是问题.第二个是静态成员的多个定义.例如,如果它包含在几个中.cpp文件,登陆到几个目标文件,然后链接器将这些对象链接在一起(例如,一个可执行文件)会有麻烦,因为它们将包含相同符号的副本.据我所知,这完全等同于在标题中的类声明下提供类外权利的情况,然后在多个地方包含这个公共标题.我记得,这会导致链接器错误.

但是,现在处理此问题的责任转移到用户/程序员.如果想要拥有一个static需要提供类外定义的库,则将其编译为单独的目标文件,然后将所有其他对象链接到此文件,因此只有一个二进制定义的副本符号.

我阅读了答案中我们是否还需要单独定义静态成员,即使它们是在类定义中初始化的?我为什么不能初始化非const静态成员或类的静态数组?.

我还是想知道:

  1. 它只是一个标准的东西,还是背后有更深层次的推理?
  2. 这可以constexpr与用户定义的文字机制一起使用.clang和g ++都说变量不能有非文字类型.也许我可以做一个.(也许出于某种原因,这也是一个坏主意)
  3. 链接器只包含一个符号副本真的是一个很大的问题吗?因为它static const应该是二进制精确的不可变副本.

如果我遗失或错误理解某事,也请评论.

And*_*zos 5

你的问题有两个部分.标准说什么?为什么会这样呢?

对于类型的静态成员,const std::string需要在类说明符之外定义它,并在其中一个转换单元中定义一个.这是One Definition Rule的一部分,在C++标准的第3节中有详细说明.

但为什么?

问题是具有静态存储持续时间的对象在最终程序映像中需要唯一的静态存储,因此需要从一个特定的转换单元链接.类说明符在一个翻译单元中没有主页,它只定义类型(在使用它的所有翻译单元中需要相同地定义).

常量积分不需要存储的原因是它被编译器用作常量表达式并在使用点内联.它永远不会成为程序图像.

但是std::string,具有静态存储持续时间的复杂类型需要存储,即使它们存在const.这是因为它们可能需要动态初始化(在进入main之前调用它们的构造函数).

您可以争辩说,编译器应该在每个使用它们的转换单元中存储有静态存储持续时间的对象的信息,然后链接器应该在链接时将这些定义合并到程序映像中的一个对象中.我猜测为什么没有这样做,是因为它需要来自链接器的太多智能.