I have a library with fortran functions that is compiled in single and double precision, but I cannot alter anything in the source code of this library. Ideally, I would define the external function as
template<typename TF> extern "C" void fortran_function(TF*)
And call the function (with both calls in the same scope) as
double a[3] = { 2, 3, 4 };
fortran_function<double>(a);
float b[3] = { 2, 3, 4 };
fortran_function<float>(b);
However, this is not allowed. How do I solve this problem in an elegant way?
There is a very strong problems with this requirement. C++ does allow overloading for native C++ functions, but not for "C"language linkages. Linkage specifications [dcl.link] §6 says:
At most one function with a particular name can have C language linkage.
And your templating attempt is equivalent to declaring explicitely:
extern "C" void fortran_function(double *);
extern "C" void fortran_function(float *);
This would declare 2 different function with C language linkage and the same name => explicitely forbidden by C++ standard.
The rationale behind that is that common implementation use name mangling to build a function identifier containing the argument types for the linker to be able to identify them. The C language linkage precisely avoid that name mangling to allow interfacing with C language functions. That immediately defeats any overloading possibility.
Anyway, you will not be able to define 2 C or Fortran functions with the same name and using different parameters. The best I can imagine is to do manual mangling :
extern "C" void fortran_function_double(double *);
extern "C" void fortran_function_float(float *);
Maybe you could use macros to ease multiple declarations, but I am really not proficient enough in macro meta-programming...
You may have to use the C preprocessor to perform name mangling on the C++ side, but on the Fortran end there is no need to use non-Fortran tools to achieve the necessary mangling. Consider
! 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
and
! 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
When compiled via gfortran -c mangle.f90
you get a mangle.o
file with subroutines fortran_function_float
and fortran_function_double
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.