【问题标题】:template External Linkage ?can anyone Explain this?模板外部链接?谁能解释一下?
【发布时间】:2010-07-27 05:50:13
【问题描述】:

模板名称具有链接 (3.5)。非成员函数模板可以有内部链接;任何其他模板名称应具有外部链接。从具有内部链接的模板生成的实体不同于在其他翻译单元中生成的所有实体。

我知道使用关键字的外部链接

extern "C"

前:

extern "C" {   template<class T>  class X { };   }

但他们给模板不得有C链接

上述陈述的真正含义是什么?

谁能解释一下?

【问题讨论】:

  • 我刚刚注意到您为该问题添加了赏金。这似乎很奇怪,因为我认为我提供的答案是正确和完整的。你还有什么不明白的? - 我注意到您还删除了问题的初始部分,使大部分答案无用......如果您仍有疑虑,您应该考虑添加 cmets 或其他问题。更改问题对任何人都没有帮助——已经回答的人不会收到通知,浏览问答的人会被不相关的答案迷惑......
  • 回滚到删除前的版本,这样更有意义。
  • @David:BE Student 似乎有兴趣专门给 USER 打分。

标签: c++ templates extern linkage


【解决方案1】:

extern "C" 声明某些东西具有C 语言链接。这不同于外部链接内部链接。默认情况下,C++ 程序中的所有内容都具有 C++ 语言链接,但您可以通过指定 extern "C++" 来重申这一点。

外部链接意味着该名称对单独编译的其他源文件可见,假设您包含正确的标题或提供正确的声明。这就是允许您在a.cpp 中定义函数foo 并从b.cpp 调用它的原因。 C++ 程序中命名空间范围内的大多数名称都有外部链接。具有内部链接没有链接的除外。您可以通过指定extern 将某些内容显式标记为具有外部链接。这与extern "C" 不同。

内部链接表示该名称对当前编译单元是唯一的,不能从其他源文件访问该变量或函数。声明为static 的文件范围变量和函数具有内部链接。此外,命名空间范围内使用常量表达式初始化的 const 整数变量默认具有内部链接,但您可以使用显式 extern 覆盖它。

最后,局部变量和类没有链接。这些名称对于声明它们的函数是本地的,并且不能从该函数外部访问。您可以使用extern 表示您确实想要访问命名空间范围内的变量。

模板不能在本地范围内定义,但可以具有内部或外部链接。

int i; // namespace scope variable has external linkage
extern int j; // explicitly mark j with external linkage
static int k; // k has internal linkage
int const n=42; // internal linkage
extern int const m=99; // external linkage

void foo(); // foo has external linkage; it may be defined in this source file or another
extern void foo(); // explicitly mark foo with external linkage
static void bar(); // bar has internal linkage, and must be defined in this source file

void foo(){} // definition of foo, visible from other source files
void bar(){} // definition of bar, not visible from other source files (internal linkage)

static void baz(){} // declare and define baz with internal linkage

template<typename T> void foobar(){} // foobar has external linkage
template<typename T>
static void foobaz(){} // foobaz has internal linkage

void wibble()
{
    int i; // local, no linkage
    extern int i; // references i, declared above with external linkage
}

extern "C"
{
    int i2; // namespace scope variable has external linkage, and "C" linkage
    extern int j2; // explicitly mark j2 with external linkage and "C" linkage
    static int k2; // k2 has internal linkage and "C" linkage
    int const n2=42; // internal linkage and "C" linkage
    extern int const m2=99; // external linkage and "C" linkage

    void foo2(); // foo2 has external linkage and "C" linkage
    static void bar2(); // bar2 has internal linkage and "C" linkage

    void foo2(){} // definition of foo2, still with external linkage and "C" linkage
    void bar2(){} // definition of bar2, still with internal linkage and "C" linkage

    static void baz(){} // declare and define baz with internal linkage
}

错误信息是正确的——模板不能有extern "C"链接。

在基本级别上,模板不能有extern "C" 链接,因为它们与 C 不兼容。特别是,模板不仅仅定义单个类或函数,而是共享相同的类或函数族名称,但通过它们的模板参数来区分。

只有一个给定名称的函数可以声明为extern "C"。当您考虑名称修饰时,这是有道理的 --- 在 C 中,函数 foo 通常在符号表中被称为 foo_foo。在 C++ 中,foo 可能有很多重载,因此签名包含在符号表中的“损坏”名称中,您可能会得到 $3fooVfoo$void 或其他东西来区分 foo(void) 和 @987654343 @等等。在 C++ 中,标记为 extern "C" 的单个重载会根据给定平台的 C 方案进行重载,而其他重载则保留其正常的重载名称。

声明模板extern "C" 将要求所有实例化为extern "C",因此与“只有一个给定名称的函数可以是extern "C"”规则相矛盾。

虽然 C 没有 structs 的名称修改,但只能有一个 struct 具有给定名称。因此,禁止 extern "C" 用于类模板也很有意义 --- 模板定义了一系列具有相同名称的类,那么哪个对应于 C struct

【讨论】:

    【解决方案2】:

    只要仔细阅读你写的引用你就会注意到,除了可能有内部链接的非成员函数模板之外,所有其他模板都有外部链接。不用加关键字,也不能加关键字。

    什么是链接的描述在§3.5/2中,特别是外部链接被定义为:

    当一个名称具有外部链接时,它所表示的实体可以被其他翻译单元的范围或同一翻译单元的其他范围的名称引用。

    要强制模板非成员函数的内部链接,您可以使用 static 关键字,但不能对其他模板执行相同操作:

    template <typename T>
    static void foo( T ) {}
    

    请注意,您可以通过使用匿名命名空间实现与内部链接类似的效果。

    内部链接:§3.5/2

    当名称具有内部链接时,它所表示的实体可以由同一翻译单元中其他范围的名称引用。

    请注意,不同之处在于它不能被其他翻译单元引用。

    namespace {
       template <typename T>
       class test {};
    }
    

    虽然未命名的命名空间不会使链接成为内部链接,但它确保不会发生名称冲突,因为它将位于 唯一 命名空间中。这种唯一性保证了其他翻译单元无法访问代码。未命名的命名空间被认为是 static 关键字 §7.3.1.1/2

    的更好替代方案

    在命名空间范围内声明对象时不推荐使用 static 关键字(见附件 D);未命名的命名空间提供了一个更好的选择

    另一方面,当你说你:

    使用关键字extern "C"了解外部链接

    你没有。 extern "C" 不是外部链接请求。重新阅读规范。 extern "C" 是一个链接规范,它指示编译器在块中使用“C”样式的链接来与已经以这种方式工作的 C 代码或库进行交互,例如 dlopen 和系列。这在第 7.5 节中进行了描述

    【讨论】:

      【解决方案3】:

      extern "C" 用于更改 C++ 函数的符号名称,以便在 C 程序中使用它们。

      在 C++ 中,函数原型在符号名称中“编码”,这是重载的要求。 但是在 C 中,您没有这样的功能。

      extern "C" 允许从 C 程序调用 C++ 函数。

      extern "C" 不是你要找的。​​p>

      你能解释一下你想做什么吗?

      【讨论】:

      【解决方案4】:

      正如我在适用于原始问题的答案中所说,更新后的问题的答案是,您误解了 extern "C" 的含义。

      序列extern "X" 允许您将以下函数或块的语言链接更改为语言X。它意味着外部链接,所以你原来的前提:

      我知道使用关键字extern "C"的外部链接

      错误。你不知道这意味着什么。参考标准中的7.5。语言链接会影响编译器如何处理参数以及它是否(以及可能如何)对符号应用名称修饰。

      抛开您对那个特定错误的坚持,编译器会抱怨您的代码,因为根据标准它是无效的。特别是§14[temp]/4:

      模板名称具有链接 (3.5)。非成员函数模板可以有内部链接;任何其他模板名称应具有外部链接。从具有内部链接的模板生成的实体不同于在其他翻译单元中生成的所有实体。 模板、模板显式特化 (14.7.3) 或类模板部分特化不应具有 C 链接。如果其中之一的链接不是 C 或 C++,则行为是实现定义的。模板定义应遵守单一定义规则(3.2)。 [注意:函数模板和类模板的成员函数的默认参数被视为模板实例化(14.5)目的的定义,并且还必须遵守一个定义规则。]

      我真的认为,在尝试评估不同编译器如何符合标准之前,您应该花时间了解标准。有问题很好,有人努力回答。表明你已经阅读了答案并试图理解它们的意思,这只是一种尊重的表现。上一个答案here最后一段的哪一部分不清楚?你读过它吗?你明白了吗?如果你没有,为什么你没有在对答案的评论中提问?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-04-07
        • 2015-12-21
        • 2015-11-23
        • 2013-05-23
        • 2017-07-23
        • 1970-01-01
        • 1970-01-01
        • 2020-06-16
        相关资源
        最近更新 更多