extern 在命名空间中如何工作?

How does extern work in namespaces?

我正在 运行创建一个类似于我发现的 here 的简单程序。它旨在减少在多个文件中包含常量时的代码膨胀。它通过在命名空间中使用 const 全局变量及其各自的 extern 前向声明来实现。

globals.h

#ifndef GLOBALS_H_
#define GLOBALS_H_

namespace Constants
{
    // forward declarations only
    extern const double pi;
    extern const double avogadro;
    extern const double my_gravity;
}

#endif

globals.cpp

namespace Constants
{
    // actual global variables
    extern const double pi(3.14159);
    extern const double avogadro(6.0221413e23);
    extern const double my_gravity(9.2); // m/s^2 -- gravity is light on this planet
}

source.cpp

#include <iostream>
#include <limits>

#include "globals.h"

int main()
{
    double value_of_pi = Constants::pi;

    std::cout << value_of_pi;

    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    std::cin.get();

    return 0;
}

我假设 Constants::pi 获取 globals.cpp 常量命名空间中包含的值 pi,并且能够这样做是因为它可以从包含的 globals.h 访问命名空间本身.我不明白的是为什么 globals.cpp 中的 const global definitions/initializations 需要 extern 关键字?我尝试删除 globals.cpp 中的 extern 关键字,认为不需要它,但没有它们我的程序不会 运行。我以为 extern 只用于前向声明?为什么 const global definitions/initializations 需要它们?与它们定义的命名空间有关吗?

It's meant to reduce code bloat when including constants in multiple files

我建议除非真的有必要,否则不要专注于这种优化,而是选择最简单的设计:直接在头文件中定义这些常量,并从所有翻译单元(.cpp)中包含该头文件文件”)需要访问这些常量。由于这些对象是 const,它们将具有内部链接,并且链接器不会因为违反单一定义规则而对您尖叫。

I tried removing the extern keywords in globals.cpp thinking that it wasn't needed, but my program won't run without them

这是因为具有静态存储持续时间的名称空间范围 const 对象(如您的 pi 变量)具有 内部链接 除非您将它们明确定义为 extern.

I thought extern was only used for forward declarations?

extern 用于声明在另一个翻译单元(.cpp 文件)中定义的变量。如果对象是 const,定义它的翻译单元需要将其显式标记为 extern,以便它具有外部链接并从其他翻译单元可见(如果该对象不是 const)。

Has it something to do with the namespace they are defined in?

不,这是所有具有静态存储持续时间的名称空间级 const 对象的规则,它在 C++ 标准的段落 [basic.link]/3 中指定:

A name having namespace scope (3.3.6) has internal linkage if it is the name of

(3.1) [...] — a variable, function or function template that is explicitly declared static; or,

(3.2) — a variable of non-volatile const-qualified type that is neither explicitly declared extern nor previously declared to have external linkage; or

(3.3) — a data member of an anonymous union.