What is proper way to call a c-function taking non-const custom pointer arguments from c++?
Take, as a very common example, the function fftw_plan_dft_1d
from FFTW3. http://fftw.org/fftw3_doc/Complex-DFTs.html#Complex-DFTs
fftw_plan fftw_plan_dft_1d(int n0,
fftw_complex *in, fftw_complex *out,
int sign, unsigned flags);
(fftw_complex
is a typedef for double[2]
).
Suppose I want apply this function to a couple of const-correct c++ containers.
std::vector<std::complex<double>> const In = {...};
std::vector<std::complex<double>> Out(In.size());
How should I do that?
_ First iteration, I have to extract the data pointer from the container,
assert(In.size() == Out.size());
fftw_plan fftw_plan_dft_1d(In.size(),
In.data(), Out.data(), // error const
FFTW_FORWARD, FFTW_ESTIMATE);
_ Second iteration
but since it is const I have to constcast.
I assume that this is the only possible solution assuming that the reason for the C-interfact is that C doesn't have const arguments.
fftw_plan p = fftw_plan_dft_1d(In.size(),
const_cast<std::complex<double>*>(In.data()), // error std::complex is not convertible to fftw_complex
Out.data(),
FFTW_FORWARD, FFTW_ESTIMATE);
_ Third iteration
Now, I have to convert std::complex<double>
to fftw_complex
(double[2]
). Fortunately std::complex<double>
is required to have the same layout as double[2]
.
fftw_plan p = fftw_plan_dft_1d(In.size(),
reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(In.data())), // is this UB?
reinterpret_cast<fftw_complex*>(Out.data()),
FFTW_FORWARD, FFTW_ESTIMATE);
and now I am paranoid, apparently reinterpret_cast
is always UB.
I don't know how to use std::launder
but I know that it can save reinterpret_cast
UB in certain situations.
fftw_plan p = fftw_plan_dft_1d(In.size(),
std::launder(reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(In.data()))), // needs c++17
std::launder(reinterpret_cast<fftw_complex*>(Out.data())),
FFTW_FORWARD, FFTW_ESTIMATE);
At the end of the day, is this a reasonable way to call a C-function that involves const and reinterpretation of types?
Am I too paranoid? or is it just that calling C from C++ is always formally UB in cases like these and I can't do anything about it?