模板外部链接?任何人都可以解释这个吗?

时间:2010-07-27 05:50:13

标签: c++ templates extern linkage

  

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

我使用关键字

了解外部链接
extern "C"

EX:

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

但是他们给模板不应该有C链接

对于上述陈述实际意味着什么?

可以解释一下吗?

4 个答案:

答案 0 :(得分:24)

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

外部链接表示该名称对于单独编译的其他源文件是可见的,假设您包含正确的标题或提供正确的声明。这使您可以在foo中定义函数a.cpp,并从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)的{​​{1}}等等。在C ++中,标记为foo(int)的单个重载根据给定平台的C方案受到损坏,而其他重载则保留其正常的错位名称。

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

虽然C没有extern "C"的名称重整,但只能有一个具有给定名称的struct。因此,struct对类模板的禁令也是有道理的---模板定义了一个具有相同名称的类族,那么哪一个对应于C extern "C"

答案 1 :(得分:8)

通过仔细阅读您编写的引用,您会注意到,除了可能具有内部链接的非成员函数模板之外,所有其他模板都具有外部链接。无需添加关键字,也无法在其中添加关键字。

§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); unnamed-namespace提供了一个更好的替代方案

另一方面,当你说你:

  

使用关键字extern "C"

了解外部关联

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

答案 2 :(得分:2)

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

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

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

extern“C”不是你想要的。

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

答案 3 :(得分:1)

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

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

  

我使用关键字extern "C"

了解外部链接

false 。你不知道它意味着什么。请参阅标准中的7.5。语言链接会影响编译器处理参数的方式,以及它是否应用(以及可能的方式)将符号重命名为符号。

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

  

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

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