使用 C 调用约定调用函数模板专门化
我有以下模板
template<typename T> void f(T t) { }
我想将其特定专业化的地址传递给 C 函数
g(&f<int>);
但由于我想要可移植,我希望“f”的调用约定与 C 的调用约定相匹配。所以我尝试了如何语言链接影响调用约定并发现
- 函数类型的语言链接影响要使用的调用约定
- 函数名称的语言链接影响重整
C++规范的语言链接部分说
在链接规范中,指定的语言链接适用于链接规范中声明的所有函数声明符的函数类型、具有外部链接的函数名称以及具有外部链接的变量名称。
因此,为了防止禁用重整(模板需要在目标文件中区分不同的专业化),我进行了如下操作,
extern "C" {
/* function name will not be affected */
template<typename T> static void f(T t) { }
}
但它给了我一个编译器错误,指出模板不能具有 C 语言链接,我认为这意味着它抱怨函数模板的函数类型。事实上,我发现规范说
模板、模板显式特化 (14.7.3) 和类模板部分特化不得具有 C 链接
现在对我来说很明显我们不想更改名称的链接,因为我们依靠重整来工作。但是禁止更改类型的链接的原因是什么?它似乎限制我们必须使用 C++ 调用约定;有人知道原因吗?是否有简单的解决方法可以实现我最初的目标?
我改变了现在尝试仅向类型提供链接的方式,如下所示
extern "C" typedef void ftype(int);
template<typename T>
ftype f;
并且效果很好。遗憾的是,在使用这种技术时,我没有找到定义 f
的方法。但无论如何,我尝试过的编译器都没有诊断出这一点(尝试过 EDG/comeau、GCC 和 clang),尽管这看起来与以前的情况完全相同:名称应该没有 C 语言链接,但只有类型有。
谁能解释一下吗?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
C 头是什么样子的?在某个地方,C 源代码必须枚举允许的回调类型。您应该利用这个机会使用一系列宏来生成各个存根函数的原型,并在 C++ 源代码中生成相应的宏序列来生成
extern "C"
存根。关于第二个问题:是的,这是可行的,但是
typedef
不在模板内。我尝试将这样的 typedef 放入类中,但事实证明,即使是类模板也不允许在extern "C"
内。所以你可以有一个函数模板,但没有依赖类型的参数。仅仅定义该函数就很容易:
啊哈,可变参数函数!
您实际上并不需要类型推导,因为它只是一个回调,因此您可以传递此
& f
到 C 代码,所有回调都具有相同的类型,并且它可以在运行时确定类型并通过可变参数传递它想要的任何内容。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 theextern "C"
. So you can have a function template, but no parameters of dependent type.Merely defining that function is easy:
Aha, variadic functions!
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.我不知道限制的原因,但是您不能使用包装器
extern "C"
函数来调用您关心的特定模板实例化吗?I don't know the reason for the restriction, but can't you use a wrapper
extern "C"
function that calls the specific template instantiation you care about?您可以从几个角度来处理它,具体取决于您想要如何配置和声明它们。
接下来有四种方法,一个命名空间演示了每一种方法。 “类型”可能是最适合您使用的。
输出:
制作:
抱歉,今晚我不会仔细研究标准——希望有所帮助。祝你好运!
you can approach it from a few angles, depending on how you want to configure and declare them.
four approaches follow, one namespace demonstrates each. 'Type' is probably the simplest for your usage.
outputs:
producing:
sorry, i'm not poring over standards tonight -- hope that helps. good luck!