我有以下模板
template<typename T> void f(T t) { }
我想将它的特定特化的地址传递给 C 函数
g(&f<int>);
但是因为我想要可移植性,我希望“f”的调用约定与 C 的调用约定匹配。所以我试验了语言链接如何影响调用约定并发现
- 函数类型的语言链接影响使用的调用约定
- 函数名的语言链接会影响修饰
C++ 规范的语言链接部分说
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.
因此,为了防止模板在目标文件中区分不同的特化需要禁用 mangling,我按如下进行
extern "C" {
/* function name will not be affected */
template<typename T> static void f(T t) { }
}
但是它给了我一个编译器错误,说模板不能有 C 语言链接,我认为这意味着它提示函数模板的函数类型。事实上,我发现规范说明
A template, a template explicit specialization (14.7.3), and a class template partial specialization shall not have C linkage
现在对我来说很明显我们不想更改 name 的链接,因为我们依赖于 mangling 来工作。但是禁止更改type 的链接的原因是什么?它似乎限制我们必须使用 C++ 调用约定;有人知道原因吗?是否有一个简单的解决方法来实现我最初的目标?
我改变了我现在尝试只给类型链接的方式,如下
extern "C" typedef void ftype(int);
template<typename T>
ftype f;
这很好用。遗憾的是,在使用这种技术时,我没有看到定义 f
的方法。但无论如何,我试过的编译器都没有诊断出这个(试过 EDG/comeau、GCC 和 clang),尽管这看起来和以前的情况完全一样:名称应该没有 C 语言链接,但只有类型有。
谁能解释一下?
最佳答案
C 头文件是什么样的?在某处,C 源代码必须枚举允许的回调类型。您应该借此机会拥有一系列宏,这些宏可为各个 stub 函数生成原型(prototype),并在 C++ 源代码中生成相应的宏序列 extern "C"
stub 。
关于第二个问题:是的,这行得通,但是 typedef
不在模板内。我试图将这样的 typedef 放入类中,但事实证明,extern "C"
中甚至不允许使用类模板。 .所以你可以有一个函数模板,但没有依赖类型的参数。
仅仅定义那个函数很简单:
extern "C" typedef void ftype(int);
template<typename T>
static ftype f; // <- added "static" here
template< typename T >
void f(int q) {}
啊哈,可变函数!
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;
}
你真的不需要类型推导,因为它只是一个回调,所以你可以传递这个 & f<int>
到 C 代码,所有回调都具有相同的类型,它可以在运行时确定类型并通过可变参数传递它想要的任何东西。
关于c++ - 使用 C 调用约定调用函数模板特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49169080/