我有一个带有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);
但是,这是不允许的。如何以优雅的方式解决这个问题?
答案 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.o
和fortran_function_float
的{{1}}个文件。