How to make a function with C-linkage from templat

2019-05-02 11:28发布

问题:

I may be a little late to know this standard statement, after seeing the SO answer:

[C++11: 7.5/1]

Two function types with different language linkages are distinct types even if they are otherwise identical.

which means, given:

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

decltype(f1) is not the same as decltype(f2)

A reason that I wasn't aware of it until now is that the major compilers (e.g. g++, clang, vc++...) don't respect this rule. See LIVE DEMO.

But I believe most people (include me) will be happier with the current nonconformant behavior. If a compiler follows the standard, many codes that bridge C and C++ would be broken.

Consider this example:

A library provides C API:

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

To use the library in C++:

void f1(void*)
{
    ...
}

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

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

To use registerCallbackInC, the callback must have C-linkage as well, however, we can't use extern "C" with template:

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
};

This makes it impossible to synthesize a C callback using template, should I consider the requirement a standard defect?

回答1:

The only restriction on templates is that the name cannot have C linkage, there is no restriction on its type, so you can use a typedef for a C linkage function in the first declaration of the template.

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