如何使用模板中的C-linkage创建函数?

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)

  • @Jamboree我实际上不确定它是否应该适用于静态成员函数,就像你在你的例子中尝试一样.在类定义中,C链接被忽略,但我不确定这是否适用于出现在类定义中的函数类型,或者是否在类中声明的函数.根据答案,你的`void X <T> :: f`可能仍然有一个带有C++链接的类型. (2认同)