9

I have the following working code:

#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';
}

Is there a good reason why it is not possible to make the test a static const ? I do understand prior to c++11 it was constrained by the standard. I thought that c++11 introduced in-class initializations to make it a little bit friendlier. I also not such semantic are available for integral type since quite some time.

Of course it works with the out-of class initialization in form of const std::string A::test = "42";

I guess that, if you can make it non-static, then the problem lies in one of the two. Initializing it out-of-class scope (normally consts are created during the instantiation of the object). But I do not think this is the problem if you are creating an object independant of any other members of the class. The second is having multiple definitions for the static member. E.g. if it were included in several .cpp files, landing into several object-files, and then the linker would have troubles when linking those object together (e.g. into one executable), as they would contain copies of the same symbol. To my understanding, this is exactly equal to the situation when ones provides the out-of-class right under the class declaration in the header, and then includes this common header in more than one place. As I recall, this leads to linker errors.

However, now the responsibility of handling this is moved onto user/programmer. If one wants to have a library with a static they need to provide a out-of-class definition, compile it into a separate object file, and then link all other object to this one, therefore having only one copy of the binary definition of the symbol.

I read the answers in Do we still need to separately define static members, even if they are initialised inside the class definition? and Why can't I initialize non-const static member or static array in class?.

I still would like to know:

  1. Is it only a standard thing, or there is deeper reasoning behind it?
  2. Can this be worked-around with the constexpr and user-defined literals mechanisms. Both clang and g++ say the variable cannot have non-literal type. Maybe I can make one. (Maybe for some reason its also a bad idea)
  3. Is it really such a big issue for linker to include only one copy of the symbol? Since it is static const all should be binary-exact immutable copies.

Plese also comment if I am missing or missunderstanding something.

4

1 回答 1

7

你的问题有两个部分。标准是怎么说的?为什么会这样?

对于 type 的静态成员const std::string,它需要在类说明符之外定义,并且在其中一个翻译单元中有一个定义。这是单一定义规则的一部分,并在 C++ 标准的第 3 条中指定。

但为什么?

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

常量积分不需要存储的原因是编译器将其用作常量表达式并在使用时内联。它永远不会进入程序图像。

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

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

于 2013-06-27T21:12:02.067 回答