模板外部链接?谁能解释一下吗?

发布于 2024-09-11 17:11:38 字数 351 浏览 11 评论 0原文

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

我知道使用关键字

extern "C"

EX 的外部链接:

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

但他们给出了模板不应有 C 链接

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

谁能解释一下吗?

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.

I know about external linkage using the keyword

extern "C"

EX :

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

but they gave template shall not have a C linkage

what actually meant for the above statement?

can any one explain this ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

不交电费瞎发啥光 2024-09-18 17:11:38

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

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

内部链接表示该名称对于当前编译单元是唯一的,您无法从其他源文件访问该变量或函数。声明为静态的文件范围变量和函数具有内部链接。此外,命名空间范围内使用常量表达式初始化的 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 可能有很多重载,因此签名会合并到符号表中的“mangled”名称中,您可能会得到 $3fooVfoo$void 或其他东西来区分 foo(void)foo(int) 等等。在 C++ 中,标记为 extern "C" 的单个重载会根据给定平台的 C 方案进行损坏,而其他重载则保留其正常的损坏名称。

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

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

extern "C" declares something to have C language linkage. This is different from external linkage and internal linkage. By default, everything in a C++ program has C++ language linkage, though you can reiterate that by specifying extern "C++".

external linkage means that the name is visible to other source files compiled separately, assuming you include the right headers or provide the right declarations. This is what allows you to define a function foo in a.cpp, and call it from b.cpp. Most names at namespace scope in a C++ program have external linkage. The exceptions are those that have internal linkage, and those that have no linkage. You can explicitly mark something as having external linkage by specifying extern. This is distinct from extern "C".

internal linkage means that the name is unique to the current compilation unit, and you cannot access the variable or function from another source file. File scope variables and functions declared static have internal linkage. Also, const integer variables at namespace scope that are initialized with a constant expression have internal linkage by default, though you can override it with an explicit extern.

Finally, local variables and classes have no linkage. The names are local to the function they are declared in, and cannot be accessed from outside that function. You can use extern to indicate that you really want to access a variable at namespace scope.

Templates cannot be defined at local scope, but may have either internal or external linkage.

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
}

The error message is correct --- templates cannot have extern "C" linkage.

At the basic level, templates cannot have extern "C" linkage because they are not compatible with C. In particular, a template doesn't just define a single class or function, but a family of classes or functions that share the same name, but are distinguished by their template parameters.

Only one function with a given name may be declared extern "C". This makes sense when you think about the name mangling --- in C, a function foo is typically called either foo or _foo in the symbol table. In C++ there may be many overloads of foo, so the signature is incorporated in the "mangled" name in the symbol table, and you might get $3fooV or foo$void or something else to distinguish foo(void) from foo(int) and so forth. In C++, the single overload that is marked extern "C" gets mangled according to the C scheme for the given platform, whereas the other overloads keep their normal mangled name.

Declaring a template extern "C" would require all instantiations to be extern "C", which thus contradicts the "only one function with a given name can be extern "C"" rule.

Though C doesn't have name mangling for structs, there can only be one struct with a given name. The ban on extern "C" for class templates thus also makes sense --- a template defines a family of classes with the same name, so which one corresponds to the C struct?

临风闻羌笛 2024-09-18 17:11:38

只要仔细阅读您所写的引用,您就会发现,除了可能具有内部链接的非成员函数模板之外,所有其他模板都具有外部链接。不需要添加关键字,那里也不能添加关键字。

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

Just by reading carefully the quote you wrote you will notice that, except non-member function templates that might have internal linkage, all other templates have external linkage. There is no need to add keywords, nor keywords can be added there.

The description of what linkage means is in §3.5/2, in particular external linkage is defined as:

When a name has external linkage, the entity it denotes can be referred to by names from scopes of other translation units or from other scopes of the same translation unit.

To force internal linkage of a template non-member function you can use the static keyword, but you cannot do the same with other templates:

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

Note that you can achieve a somehow similar effect as internal linkage by using anonymous namespaces.

Internal linkage: §3.5/2

When a name has internal linkage, the entity it denotes can be referred to by names from other scopes in the same translation unit.

Note that the difference is that it cannot be referred from other translation units.

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

While the unnamed namespace does not make the linkage internal, it ensures that there will be no name collision as it will be in a unique namespace. This uniqueness guarantees that the code is not accessible from other translation units. Unnamed namespaces are considered to be a better alternative to the static keyword §7.3.1.1/2

The use of the static keyword is deprecated when declaring objects in a namespace scope (see annex D); the unnamed-namespace provides a superior alternative

On the other hand, when you say that you:

know about external linkage using the keyword extern "C"

You don't. extern "C" is not a request for external linkage. Reread the spec. extern "C" is a linkage-specification and instructs the compiler to use "C" style linkage within the block to interact with C code or libraries that already work that way, like dlopen and family. This is described in §7.5

街角迷惘 2024-09-18 17:11:38

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

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

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

extern "C" 不是您要找的。

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

extern "C" is used to change symbol name of C++ function in order to use them from a C program.

In C++, function prototype is "coded" in symbol name, this is a requirement for overloading.
But in C, you don't have a such feature.

extern "C" allow to call C++ function from a C program.

extern "C" is not what you are looking for.

Could you please explain what do you want to do ?

混吃等死 2024-09-18 17:11:38

正如我在适用于原始问题的答案中已经说过的那样,更新问题的答案是,您误解了 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) 目的的定义,并且还必须遵守单一定义规则。]

我真的认为在尝试评估不同编译器如何遵守标准 您应该花时间去理解该标准。有问题很好,有人会努力回答。表明您已阅读答案并尝试理解其含义只是一种尊重的表现。 这里是上一个答案最后一段的哪一部分 不清楚吗?你读过吗?你明白了吗?如果没有,为什么不在评论中询问答案?

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?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文