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

Wan*_*ool 6 c++ namespaces const global-variables extern

我正在运行一个类似于我在这里找到的简单程序.这意味着在多个文件中包含常量时减少代码膨胀.它通过在命名空间中使用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
Run Code Online (Sandbox Code Playgroud)

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
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

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

And*_*owl 11

这意味着在多个文件中包含常量时减少代码膨胀

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

我尝试删除globals.cpp中的extern关键字,认为它不需要,但我的程序不会在没有它们的情况下运行

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

我以为extern只用于前言声明?

extern用于声明在另一个转换单元(".cpp文件")中定义的变量.如果对象是const,则定义它的翻译单元需要明确地将其标记extern为使其具有外部链接并且从其他翻译单元可见(如果对象不是,则不需要这样const).

它与定义的命名空间有关吗?

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

具有命名空间作用域(3.3.6)的名称具有内部链接(如果它的名称)

(3.1)[...] - 显式声明为静态的变量,函数或函数模板; 要么,

(3.2) - 非易失性const限定类型的变量,既未明确声明为extern,也未声明为具有外部链接 ; 要么

(3.3) - 匿名工会的数据成员.

  • 我觉得半被迫投反对票,因为你没有指出他的场景是多么愚蠢,而是只关注语言律师,这对提问者的价值有限。 (2认同)
  • @WanderingFool:它们是命名空间级别,它们通常被称为"全局",因为它们不在块范围内,但这也不完全准确,因为它们不是全局命名空间的一部分.它们具有静态存储持续时间,在`main()`输入之前创建并在它离开后被销毁,但它们确实存在于`Constants`命名空间中,为了访问它们的名称,你必须指定`Constants ::`(或通过using指令或使用声明隐式地实现.我猜最后一个问题的答案是"是":由于标题,名称可见 (2认同)