C interoperability with assumed-shape arrays

If you use C++17 (or higher), you can have high level code just like in Fortran.

#include <array>
#include <numeric>

#include "Fcpp.h" // <-- C++ descriptor adaptor

// Fortran routine
extern "C" void sub(CFI_cdesc_t *);

int main(void)
{
    using namespace Fcpp;

    std::array<int,5> x;
    std::iota(x.begin(),x.end(),42); // or std::ranges::iota(x,42) in C++23

    sub(desc(x)); /* Create adaptor on the fly */

    return 0;
}
~/tmp$ gfortran-13 -c m.f90     # module providing routine sub
~/tmp$ g++-13 -Wall -std=c++17 wrapper.cpp m.o -lgfortran
~/tmp$ ./a.out
 In Fortran sub: size(x) =            5
          42          43          44          45          46

How does it work? Well you create an adaptor using a templated class; all the ugly work is hidden in the constructor. Click on the little arrow (triangle) for a look at the internals:

Fcpp - Adaptor between C++ and Fortran
#include <cassert>
#include <array>
#include <vector>

#include "ISO_Fortran_binding.h"

namespace Fcpp {

    namespace {

        // Type converters
        template<typename T>
        constexpr CFI_type_t type(){ return CFI_type_other; };
        template<>
        constexpr CFI_type_t type<float>(){ return CFI_type_float; } 
        template<>
        constexpr CFI_type_t type<double>(){ return CFI_type_double; } 
        template<>
        constexpr CFI_type_t type<int>(){ return CFI_type_int; } 

    }

// Descriptor Adaptor - provides Fortran descriptor of a C++ entity
template<typename T>
class desc {
public:

    desc(T* ptr, int n0) {

        CFI_index_t extents[] = { 
            static_cast<CFI_index_t>(n0)};

        [[maybe_unused]] int status = CFI_establish(
            this->get(),
            ptr,
            CFI_attribute_other,
            type<T>(),
            sizeof(T),
            1,
            extents
        );

        assert(status == CFI_SUCCESS);

    }

    // Constructor from std::vector
    desc(std::vector<T> &buffer) : desc(buffer.data(),buffer.size()) {}

    // Constructor from std::array
    template<std::size_t N>
    desc(std::array<T,N> &buffer) : desc(buffer.data(),N) {}

    // Return pointer to the underlying descriptor
    constexpr auto get() const { 
      return (CFI_cdesc_t *) &desc_; 
    }

    // Implicit cast to C-descriptor pointer
    operator CFI_cdesc_t* () { return this->get(); }

private:
   CFI_CDESC_T(1) desc_;
};

} // namespace Fcpp
3 Likes