5

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

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

extern "C"

前任 :

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

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

上述声明的实际含义是什么?

谁能解释一下?

4

4 回答 4

26

extern "C"声明有C 语言链接的东西。这不同于外联动内联动。默认情况下,C++ 程序中的所有内容都具有 C++ 语言链接,尽管您可以通过指定extern "C++".

外部链接意味着该名称对单独编译的其他源文件可见,假设您包含正确的标题或提供正确的声明。这就是允许您在 中定义函数并从fooa.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,因此签名包含在符号表中的“损坏”名称中,您可能会得到$3fooVorfoo$void或其他东西来区分foo(void)等等foo(int)。在 C++ 中,标记的单个重载extern "C"会根据给定平台的 C 方案进行重载,而其他重载则保留其正常的重载名称。

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

尽管 C 没有对structs 进行名称修饰,但只能有一个struct具有给定名称的名称。因此,禁止extern "C"类模板也是有道理的——模板定义了一系列具有相同名称的类,那么哪个对应于 C struct

于 2010-08-08T22:29:49.393 回答
9

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

§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 节中进行了描述

于 2010-07-27T08:08:18.077 回答
2

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

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

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

extern "C" 不是你要找的。

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

于 2010-07-27T06:22:06.550 回答
1

The answer to the updated question is, as I already said in the answer that applies to the original question, that you are misunderstanding what extern "C" means.

The sequence extern "X" allows you to change the language linkage of the following function or block to language X. It does not mean external linkage, so your original premise:

I know about external linkage using the keyword extern "C"

is false. You don't know what it means. Refer to 7.5 in the standard. Language linkage affects how the compiler processes parameters and whether it applies (and potentially how) name mangling to the symbols.

Taking aside your insistence in that particular error, the compiler is complaining about your code because it is invalid according to the standard. In particular §14[temp]/4:

A template name has linkage (3.5). A non-member function template can have internal linkage; any other template name shall have external linkage. Entities generated from a template with internal linkage are distinct from all entities generated in other translation units. A template, a template explicit specialization (14.7.3), or a class template partial specialization shall not have C linkage. If the linkage of one of these is something other than C or C++, the behavior is implementation-defined. Template definitions shall obey the one definition rule (3.2). [Note: default arguments for function templates and for member functions of class templates are considered definitions for the purpose of template instantiation (14.5) and must also obey the one definition rule.]

I really think that before trying to evaluate how different compilers comply with the standard you should take your time to understand the standard. It is quite fine to have questions, and there is people making an effort to answer them. Showing that you have read the answers and tried to grasp what they mean is just a sign of respect. What part of the last paragraph in the previous answer here is unclear? Did you read it? Did you understand it? If you didn't, why did you not ask in a comment to the answer?

于 2010-08-07T21:32:05.733 回答