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

时间:2014-10-03 06:55:52

标签: c++ templates language-lawyer linkage

在看到SO answer

后,我可能有点迟到知道这个标准声明

[C ++ 11:7.5 / 1]

  

具有不同语言联系的两种函数类型是不同的类型,即使它们在其他方面是相同的。

这意味着,给定:

void f1();
extern "C" void f2();

decltype(f1)decltype(f2)

不同

直到现在我还没有意识到这一点的原因是主要的编译器(例如g ++,clang,vc ++ ......)不尊重这个规则。请参阅LIVE DEMO

但我相信大多数人(包括我)会对当前的不一致的行为感到高兴。 如果编译器遵循标准,许多桥接C和C ++的代码将被破坏。

考虑这个例子:

库提供C API:

#ifdef __cplusplus
extern "C" {
#endif
void registerCallbackInC(void(*callback)(void*));
#ifdef __cplusplus
}
#endif

在C ++中使用库:

void f1(void*)
{
    ...
}

extern "C" void f2(void*)
{
    ...
}

registerCallbackInC(f1); // invalid, f1 has C++ linkage
registerCallbackInC(f2); // OK

要使用registerCallbackInCcallback也必须具有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
};

这使得无法使用模板合成C回调,我是否应该将该要求视为标准缺陷?

1 个答案:

答案 0 :(得分:8)

对模板的唯一限制是名称不能具有C链接,对其类型没有限制,因此您可以在模板的第一个声明中使用typedef作为C链接函数。

extern "C" typedef void cfunc();
template <typename T> cfunc yourfunc;
template <typename T> void yourfunc() { }