Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
108 views
in Technique[技术] by (71.8m points)

c++ - Calling function template specialization using C calling conventions

I have the following template

template<typename T> void f(T t) { }

And I want to pass the address of a specific specialization of it to a C function

g(&f<int>);

But as I want to be portable, I want the calling convention of "f" to match the one of C. So I experimented how language linkage affects calling convention and found

  • The language linkage of the function type affects calling convention to use
  • The language linkage of the function name affects mangling

The language linkage section of the C++ spec says

In a linkage-specification, the speci?ed language linkage applies to the function types of all function declarators, function names with external linkage, and variable names with external linkage declared within the linkage-specification.

So to prevent disabling of mangling, which is needed for templates to distinguish different specializations from each other in the object file, I went as follows

extern "C" {
    /* function name will not be affected */
    template<typename T> static void f(T t) { }
}

But it gives me a compiler error saying that templates cannot have C language linkage, which I take it to mean that it complains about the function template's function type. And in fact, I found the spec to say

A template, a template explicit specialization (14.7.3), and a class template partial specialization shall not have C linkage

Now it's obvious to me that we don't want to change the name's linkage, because we rely on mangling to work. But what is the reason for forbidding to change the type's linkage? It seems to restrict us to having to use C++ calling convention; does someone know the reason, and whether there is an easy work around to achieve my initial goal?


I changed the way I try to give linkage to only the type now, as follows

extern "C" typedef void ftype(int);

template<typename T>
ftype f;

And this works fine. Sadly, I don't see a way to define f when using this technique. But anyway, no compiler I tried diagnoses this (tried EDG/comeau, GCC and clang), even though this looks like exactly the same situation as before: The name should have no C language linkage, but only the type has.

Can anyone explain this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

What does the C header look like? Somewhere, the C source must enumerate the callback types allowed. You should take that opportunity to have a series of macros that generate prototypes to individual stub functions, with a corresponding sequence of macros in the C++ source generating extern "C" stubs.


As to the second question: Yes, that works, but the typedef is not inside a template. I attempted to put such a typedef inside a class, but it turns out that even class templates are not allowed inside the extern "C". So you can have a function template, but no parameters of dependent type.

Merely defining that function is easy:

extern "C" typedef void ftype(int);

template<typename T>
static ftype f; // <- added "static" here

template< typename T >
void f(int q) {}

Aha, variadic functions!

extern "C" typedef void ftype( int, ... );

template<typename T>
static ftype f;

template< typename T >
static void f( int z, ... ) {
    va_list va;
    va_start( va, z );
    T v = va_arg( va, T );
    va_end( va );

    std::cout << v;
}

You don't really need type deduction since it's just a callback, so you can pass this & f<int> to the C code, all callbacks having the same type, and it can make the type determination at runtime and pass whatever it wants through the varargs.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...