使用C调用约定调用函数模板专门化 [英] Calling function template specialization using C calling conventions

查看:133
本文介绍了使用C调用约定调用函数模板专门化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下模板

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

我想传递一个特定的到C函数

  g(& f< int>); 

但是当我想要可移植时,我想要调用约定f因此我尝试了语言链接如何影响调用约定并发现




  • 影响调用约定使用

  • 函数名称的语言链接会影响到



C ++规范的语言链接部分说明


在链接规范中,指定的语言链接适用于函数


所以,在所有的函数声明符中,所有函数声明符的类型,外部链接的函数名和外部链接的变量名。防止禁止崩溃,这是模板需要在对象文件中区分不同的专业化,我去了如下

  externC{
/ *函数名不受影响* /
template< typename T> static void f(T t){}
}

说模板不能有C语言链接,我认为它意味着它抱怨函数模板的函数类型。事实上,我发现规范说


模板,模板显式特化(14.7.3)和类模板partial专业化不应该有C链接


现在很明显我们不想更改名称的链接,因为我们依赖于mangling工作。但是,禁止更改类型链接的原因是什么?似乎限制了我们必须使用C ++调用约定;有人知道原因,以及是否有一个容易的工作来实现我的初始目标?






现在我尝试只链接类型,如下

  externCtypedef void ftype(int); 

template< typename T>
ftype f;

可悲的是,我没有看到一个方法来定义 f 使用这种技术。但无论如何,没有编译器我试图诊断这(尝试EDG /来,GCC和铛),虽然这看起来完全相同的情况,以前:名称应该没有C语言链接,但只有类型有。



任何人都可以解释这个问题?

解决方案

看起来像?某处,C源必须枚举允许的回调类型。你应该利用这个机会有一系列的宏生成单个存根函数的原型,在C ++源中生成 externC存根的宏的相应序列。 / p>




至于第二个问题:是的,可以,但 typedef 不在模板内。我试图把这样的typedef在类中,但事实证明,即使类模板不允许在 externC。所以你可以有一个函数模板,但没有依赖类型的参数。



只需简单定义该函数:

  externCtypedef void ftype(int); 

template< typename T>
static ftype f; //< - addedstatichere

template<类型名T>
void f(int q){}



<

  externCtypedef void ftype(int,...); 

template< typename T>
static ftype f;

template<类型名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;
}

你不需要真正的类型扣除,因为它只是一个回调,所以你可以通过这个& f< int> 到C代码,所有回调都具有相同的类型,并且它可以在运行时进行类型确定,并通过varargs传递它想要的类型。


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 specified 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?

解决方案

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.

这篇关于使用C调用约定调用函数模板专门化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆