模板外部“C”函数从C ++调用不同类型的Fortran函数

时间:2018-06-01 13:47:34

标签: c++ templates fortran extern

我有一个带有fortran函数的库,它以单精度和双精度编译,但我不能改变这个库的源代码中的任何内容。理想情况下,我将外部函数定义为

template<typename TF> extern "C" void fortran_function(TF*)

并调用该函数(两个调用在同一范围内)和

double a[3] = { 2, 3, 4 };
fortran_function<double>(a);

float b[3] = { 2, 3, 4 };
fortran_function<float>(b);

但是,这是不允许的。如何以优雅的方式解决这个问题?

2 个答案:

答案 0 :(得分:2)

此要求存在非常严重的问题。 C ++确实允许对本机C ++函数进行重载,但不允许对“C”语言链接进行重载。链接规范[dcl.link]§6说:

  

最多一个具有特定名称的函数可以具有C语言链接。

你的模板尝试相当于明确宣告:

extern "C" void fortran_function_double(double *);
extern "C" void fortran_function_float(float *);

这将声明2个不同的函数与C语言链接和相同的名称=&gt; C ++标准明确禁止。

背后的基本原理是,通用实现使用 name mangling 来构建一个函数标识符,其中包含链接器能够识别它们的参数类型。 C语言链接精确地避免了名称修改以允许与C语言函数的接口。这会立即抵消任何超载的可能性。

无论如何,您将无法使用相同的名称和使用不同的参数定义2 C或Fortran函数。我能想象的最好的是做手动修改

<textarea #textArea>{{text}}</textarea>

也许你可以使用宏来简化多个声明,但我真的不够精通宏元编程......

答案 1 :(得分:2)

您可能必须使用C预处理器在C ++端执行名称修改,但在Fortran端,不需要使用非Fortran工具来实现必要的修改。考虑

! mangle.i90

subroutine mangle(x) bind(C,name='fortran_function_'// &
   trim(merge('float ','double',mykind==C_FLOAT)))
   real(mykind) x(3)
   x([2,3,1]) = x
end subroutine mangle

! mangle.f90

module floatmod
   use ISO_C_BINDING
   implicit none
   integer, parameter :: mykind = C_FLOAT
   contains
include 'mangle.i90'
end module floatmod

module doublemod
   use ISO_C_BINDING
   implicit none
   integer, parameter :: mykind = C_DOUBLE
   contains
include 'mangle.i90'
end module doublemod

通过gfortran -c mangle.f90汇编后,您会收到包含子例程mangle.ofortran_function_float的{​​{1}}个文件。