Dan*_*ien 26 c++ templates extern linkage
这是一个后续问题的答案,以是否有可能的typedef指针到extern-"C" -函数模板中的类型?
此代码无法使用g++Visual C/C++和Comeau C/C++进行编译,并且具有基本相同的错误消息:
#include <cstdlib>
extern "C" {
static int do_stuff(int) {
return 3;
}
template <typename return_t_, typename arg1_t_>
struct test {
static void foo(return_t_ (*)(arg1_t_)) { }
};
}
int main()
{
test<int, int>::foo(&do_stuff);
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
g ++说"错误:带C链接的模板",Visual C/C++发出编译器错误C2894,而Comeau C/C++说"错误:此声明可能没有extern"C"链接".
问题是,所有人都满意:
#include <cstdlib>
extern "C" {
static int do_stuff(int) {
return 3;
}
struct test {
static void foo(int (*)(int)) { }
};
}
int main()
{
test::foo(&do_stuff);
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
C++标准的第7.5节"链接规范"规定:
对于类成员的名称和类成员函数的成员函数类型,将忽略AC语言链接.
它甚至给出了一个例子:
extern "C" {
class X {
void mf(); // the name of the function mf and the member
// function's type have C++ language linkage
void mf2(void(*)()); // the name of the function mf2 has C++ language
// linkage; the parameter has type pointer to C function
};
}
Run Code Online (Sandbox Code Playgroud)
如果在extern"C"块中允许模板,那么实例化的成员函数将具有C++链接.
那么,为什么C++ 98 Standard的第14章模板状态如下:
模板名称可能具有链接(3.5).模板,模板显式特化(14.7.3)和类模板部分特化不应具有C链接.
模板"可能"具有联系意味着什么?什么是模板链接?
为什么它明确禁止具有与C链接的模板,当一个类是好的,和模板(默认构造函数,析构函数和赋值运算符重载)的实例的所有成员函数将有C++联动?
Mar*_*som 14
模板不是实际代码,它们只是编译器的指南,用于在知道模板参数后如何生成代码.因此,在您尝试使用它们之前,它们实际上并不存在.您无法提供与不存在的内容的链接.
Fre*_*urk 11
模板"可能"具有联系意味着什么?什么是模板链接?
所有名称都有外部链接,内部链接或没有链接(C++03§3.5p2),但这与语言链接不同.(令人困惑,我知道.C++ 0x也会通过链接大大改变一切.)用作模板参数的任何东西都需要外部链接:
void f() {
struct S {};
vector<S> v; // Not allowed as S has internal linkage.
}
Run Code Online (Sandbox Code Playgroud)
请注意,C++ 98有"可能"在你所引述§14p4的,但C++ 03中删除"可能",因为模板不能将给他们内在联系上下文声明:
void f() {
// Not allowed:
template<class T>
struct S {};
}
Run Code Online (Sandbox Code Playgroud)
因为extern C禁用名称修改,哪些模板使用
要查看模板是通过名称修改实现的,请编译和反编译:
#include <cassert>
template <class C>
C f(C i) { return i; }
int main() {
f<int>(1);
f<double>(1.5);
}
Run Code Online (Sandbox Code Playgroud)
和:
g++ -c -g -std=c++98 main.cpp
objdump -Sr main.o
Run Code Online (Sandbox Code Playgroud)
输出包含:
int main() {
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 10 sub $0x10,%rsp
f<int>(1);
8: bf 01 00 00 00 mov $0x1,%edi
d: e8 00 00 00 00 callq 12 <main+0x12>
e: R_X86_64_PC32 _Z1fIiET_S0_-0x4
f<double>(1.5);
12: 48 b8 00 00 00 00 00 movabs $0x3ff8000000000000,%rax
19: 00 f8 3f
1c: 48 89 45 f8 mov %rax,-0x8(%rbp)
20: f2 0f 10 45 f8 movsd -0x8(%rbp),%xmm0
25: e8 00 00 00 00 callq 2a <main+0x2a>
26: R_X86_64_PC32 _Z1fIdET_S0_-0x4
}
2a: b8 00 00 00 00 mov $0x0,%eax
2f: c9 leaveq
30: c3 retq
Run Code Online (Sandbox Code Playgroud)
请注意如何将所有callq名称都称为_Z1fIiET_S0_.
其他依赖于名称修改的特性也是如此,例如函数重载。
我写了一个更详细的答案:在 C++ 中 extern "C" 的作用是什么?