【问题标题】:Example of entity declared in a anonymous namespace that has external linkage在具有外部链接的匿名命名空间中声明的实体示例
【发布时间】:2014-11-19 12:00:00
【问题描述】:

鉴于以下 §3.5/4 中的陈述(强调我的)和 §7.3.1.1/1 中的注释 [94],我想有一个在未命名命名空间中声明的实体的单个示例,该命名空间具有外部联动。

§3.5/4

未命名的命名空间或直接或间接声明的命名空间 在未命名的命名空间中具有内部链接。所有其他命名空间 有外部联系。 名称空间范围尚未被 上面给定的内部链接与封闭的链接具有相同的链接 命名空间,如果是

的名字
  • 一个变量;或
  • 一个函数;或
  • 命名类(第 9 条),或在 typedef 声明中定义的未命名类,其中该类具有用于链接的 typedef 名称 目的(7.1.3);或
  • 命名枚举 (7.2),或在 typedef 声明中定义的未命名枚举,其中枚举的 typedef 名称为 链接目的(7.1.3);或
  • 属于具有链接的枚举的枚举数;或
  • 一个模板。

第 7.3.1.1/1 节的注释 [94]:

虽然未命名命名空间中的实体可能具有外部链接, 他们有效地被他们的翻译所独有的名字所限定 单位,因此永远无法从任何其他翻译单位看到。

【问题讨论】:

  • 我怀疑脚注可能是 C++03 的遗留物,其中未命名命名空间中的名称具有外部链接(因为否则它们不能用作模板参数)。作者只是忘记删除它。

标签: c++ c++11 namespaces language-lawyer linkage


【解决方案1】:

例如

#include <iostream>

namespace
{
    extern int x = 10;

    void f( int y )
    {
        extern int x;
        std::cout << x + y << std::endl;
    }
}

int main() 
{
    int y =  15;

    f( y );

    return 0;
}

根据 C++ 标准

6 在块范围内声明的函数的名称和一个 由块范围外部声明声明的变量具有链接。如果 存在具有链接的实体的可见声明 相同的名称和类型,忽略在最里面声明的实体 封闭命名空间范围,块范围声明声明 相同的实体并接收前一个声明的链接。如果 有不止一个这样的匹配实体,程序是 格式不正确。否则,如果没有找到匹配的实体,则块范围 实体接收外部链接

【讨论】:

  • 我相信 §3.5/2 第一个要点中的 or 不是排他性的。所以,我不同意 x 在您的示例中具有外部链接。
  • @Wake up Brazil x Os automatica 变量,用 quakifier extern 声明。因此,如果在封闭的命名空间中有前面的 x 声明,则 x 具有相同的链接。参见 3.5/6。
  • §3.5/6 只是告诉您本地 x 与在命名空间范围 extern int x = 10; 中声明的 x 具有相同的链接。但这并不意味着这个x 具有外部链接。请参阅 §3.5/4 第一个要点:A name having namespace scope that has not been given internal linkage above has the same linkage as the enclosing namespace if it is the name of — a variable;。另请参阅引用 §3.5 的 §7.1.1/6,关于使用 extern 说明符声明的名称的链接。
  • @Wake up Brazil 看来您不明白您阅读的内容。变量 x 被定义为在未命名的命名空间中具有外部链接。函数中声明的局部变量也具有外部链接,因为在封闭的命名空间中有一个具有相同名称和链接的变量。有什么问题?!。
【解决方案2】:

这是一个很好的问题,因为它很难演示。我们可以利用 C++ 标准中的其他规则来表明匿名命名空间中的变量可以具有外部链接。

在具有外部链接的 int* 上进行模板化将成功,而在具有内部链接的 int* 上进行模板化将失败。

#include <iostream>

namespace {
    // not externally linked, won't compile
    // const int i = 5;

    // external linkage, compiles
    extern int i;
    int i = 5;
}

template<int* int_ptr>
struct temp_on_extern_linked_int {
    temp_on_extern_linked_int() {
        std::cout << *int_ptr << std::endl;
    }
};

int main() {
    temp_on_extern_linked_int<&i>();
}

如图所示,程序编译运行。

$ g++-4.8 main.cpp -o main
$ ./main
5

取消注释i 的其他定义会导致编译失败。

$ g++-4.8 main.cpp -o main
main.cpp: In function 'int main()':
main.cpp:17:30: error: '& {anonymous}::i' is not a valid template argument of
type 'int*' because '{anonymous}::i' does not have external linkage
  temp_on_extern_linked_int<&i>();
                              ^

编译器很有帮助。它明确指出因为i 没有外部链接,所以编译失败。

i 的注释定义具有内部链接,因为它是限定的 const 而没有 extern。 (§3.4.6)

Variables at namespace scope that are declared const and not extern have internal linkage.

部分技巧不是编译为 C++11。

Why did C++03 require template parameters to have external linkage?

【讨论】:

  • AFAIK 您已经证明未命名的命名空间在 C++03 中具有外部链接,因此您甚至不需要声明 extern int i;,因为编译器将声明 int i = 5; 识别为有外部联系。
  • 对于 C++11,我只能向您引用标准,但由于您已经在 OP 中提供了相关引用,因此不清楚您在寻找什么。知道命名空间和其中的变量不一定具有相同的链接是否有帮助?
  • 另外,C++11 中破坏示例的变化是模板参数,而不是链接规则。
  • 在 C++11 中代码编译是因为声明 extern int i; 没有向声明 int i = 5; 添加任何内容,即变量 i 继续具有内部链接,尽管 @ 987654334@ 说明符。
【解决方案3】:

您正在查看标准中的缺陷。

使未命名的命名空间成员具有内部链接的更改发生在 C++11 标准化过程的后期,即 2010 年 11 月 (CWG issue 1113)。结果,标准中的许多地方需要更改,但没有更改。其中之一是您引用的脚注。

CWG issue 1603,目前处于“准备就绪”状态(阅读:该决议可能会在下一次委员会会议上通过),将解决此问题以及与为未命名的命名空间成员提供内部链接相关的许多其他问题。

【讨论】:

  • 这正是我想要的。很好的答案 (+1)。
猜你喜欢
  • 1970-01-01
  • 2018-09-10
  • 2012-06-05
  • 1970-01-01
  • 2015-01-07
  • 1970-01-01
  • 2011-05-10
  • 2020-08-19
相关资源
最近更新 更多