Jam*_*ree 5 c++ templates linkage language-lawyer
在看到SO答案后,我可能有点迟到知道这个标准陈述:
[C++ 11:7.5/1]
具有不同语言链接的两种函数类型是不同的类型,即使它们在其他方面是相同的.
这意味着,给定:
void f1();
extern "C" void f2();
Run Code Online (Sandbox Code Playgroud)
decltype(f1) 是不一样的 decltype(f2)
直到现在我才意识到的一个原因是主要的编译器(例如g ++,clang,vc ++ ......)不遵守这个规则.见现场演示.
但我相信大多数人(包括我)会对当前不符合标准的行为感到高兴.如果编译器遵循标准,许多桥接C和C++的代码将被破坏.
考虑这个例子:
库提供C API:
#ifdef __cplusplus
extern "C" {
#endif
void registerCallbackInC(void(*callback)(void*));
#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)
要在C++中使用库:
void f1(void*)
{
...
}
extern "C" void f2(void*)
{
...
}
registerCallbackInC(f1); // invalid, f1 has C++ linkage
registerCallbackInC(f2); // OK
Run Code Online (Sandbox Code Playgroud)
要使用registerCallbackInC,callback必须有C-linkage,但是,我们不能使用extern "C"模板:
extern "C"
{
template<class T>
void f(void*); // invalid
}
template<class T>
extern "C" void f2(void*); // invalid
template<class T>
struct F
{
extern "C" static void f(void*); // invalid
};
Run Code Online (Sandbox Code Playgroud)
如果我认为需求是标准缺陷,这就无法使用模板合成C回调?
小智 9
模板的唯一限制是名称不能具有C链接,其类型没有限制,因此您可以在模板的第一个声明中使用typedef作为C链接函数.
extern "C" typedef void cfunc();
template <typename T> cfunc yourfunc;
template <typename T> void yourfunc() { }
Run Code Online (Sandbox Code Playgroud)