[英]Template an extern “C” function to call Fortran functions from C++ with different types
我有一個帶有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);
但是,這是不允許的。 如何以一種優雅的方式解決這個問題?
此要求存在非常強烈的問題。 C ++確實允許對本機C ++函數進行重載,但不允許對“ C”語言鏈接進行重載。 鏈接規范[dcl.link]§6說:
具有特定名稱的函數最多可以具有C語言鏈接。
而您的模板嘗試等同於顯式聲明:
extern "C" void fortran_function(double *);
extern "C" void fortran_function(float *);
這將聲明兩個具有C語言鏈接的不同功能,並且C ++標准明確禁止使用相同的名稱=>。
其基本原理是,通用實現使用名稱修飾來構建函數標識符,該函數標識符包含用於鏈接器能夠識別它們的參數類型。 C語言鏈接恰好避免了名稱混用,以允許與C語言功能進行接口。 這立即消除了任何超載的可能性。
無論如何,您將無法使用相同的名稱和使用不同的參數來定義2 C或Fortran函數。 我能想象的最好的辦法是手動操作 :
extern "C" void fortran_function_double(double *);
extern "C" void fortran_function_float(float *);
也許您可以使用宏來簡化多個聲明,但是我真的對宏元編程還不夠熟練。
您可能必須使用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
編譯時,您將得到一個包含子例程fortran_function_float
和fortran_function_double
的mangle.o
文件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.