अक्सर मुझे अपने सी ++ कोड से कुछ फोरट्रान रूटीन कॉल करना पड़ता है। मेरे मामले में, एक सी हेडर हमेशा उपलब्ध होता है और इसमें हस्ताक्षर होते हैं जैसे कि

double fFortran(int* a, int* b, double* someArray, int* sizeOfThatArray)

मेरा प्रश्न है: क्या एक सामान्य सी ++ 14 रैपर fortranCall लिखना संभव होगा (शायद टेम्पलेट मेटाप्रोग्रामिंग का उपयोग कर) जहां आवश्यक हो वहां पते लेता है और फिर फोरट्रान फ़ंक्शन को कॉल करता है इस तरह

double someArray[2] = {1, 4};
double result = fortranCall(fFortran, 4, 5, someArray,
    sizeof(someArray) / sizeof(someArray[0]));

जो के बराबर होना चाहिए

double someArray[2] = {1, 4};
int sizeOfSomeArray = sizeof(someArray) / sizeof(someArray[0]);
int a = 4;
int b = 5;
double result = fFortran(&a, &b, someArray, &sizeOfSomeArray);

मुझे लगता है कि सही समाधान में पैरामीटर पैक शामिल हैं लेकिन मैं यह नहीं समझ सकता कि कैसे एक से अधिक पुनरावृत्त करना है और जहां आवश्यक हो वहां संदर्भ लेना है।

5
StefKKK 19 अप्रैल 2019, 19:53

1 उत्तर

सबसे बढ़िया उत्तर

इस उत्तर के लिए मैं निम्नलिखित धारणाएँ बनाऊँगा:

  • फोरट्रान फ़ंक्शंस के पैरामीटर सभी पॉइंटर्स के रूप में पास किए जाते हैं
  • सूचक पते fortranCall फ़ंक्शन को दिए गए पैरामीटर से प्राप्त किए जाने हैं।
  • सरणी सूचक पैरामीटर हमेशा सरणी के आकार के सूचक द्वारा पीछा किया जाएगा
  • हम मापदंडों के क्रम को संरक्षित करना चाहते हैं।

उदाहरण कॉल:

// So, given function signature
double fFortran(int* a, int* b, double* someArray, int* sizeOfThatArray);
// we would like to call with:
fortranCall(fFortran, 4, 5, someArray);

// Likewise, given
fFortranTwoArrays(double* arrayA, int* size_of_A, double* arrayB, int* size_of_B);
// we would like to call with
fortranCall(fFortranTwoArrays, someArray, some_other_Array);

निम्नलिखित प्रोग्राम ऊपर दिखाए गए अनुसार कॉल करेगा:

#include <tuple>
#include <type_traits>

// Functions to call eventually
double fFortran(int* a, int* b, double* someArray, int* sizeOfThatArray)
{ 
    return 0.0; 
}

double fFortranTwoArrays(double* arrayA, int* size_of_A, double* arrayB, int* size_of_B)
{ 
    return 0.0; 
}

// If T is an array 
// then make a std::tuple with two parameters
//   pointer to first of T and 
//   pointer to extent of T
template<
    typename T,
    typename std::enable_if <
        std::is_array<T>{},
        int
    >::type Extent = std::extent<T>::value,
    typename Ptr = typename std::decay<T>::type
>
auto make_my_tuple(T& t)
{
    static auto extent = Extent;
    Ptr ptr = &t[0];
    return std::make_tuple(ptr, &extent);
}

// If T is not an array 
// then make a std::tuple with a single parameter
//   pointer to T
template<typename T,
    typename std::enable_if <
        !std::is_array<T>{},
        int
    >::type = 0 
>
auto make_my_tuple(T& t)
{
    return std::make_tuple(&t);
}

template<typename F, typename... Targs>
auto fortranCall(F& f, Targs&& ... args)
{
    // Make a single tuple with all the parameters.
    auto parameters = std::tuple_cat(make_my_tuple(args)...);

    // Arrays were each expanded to 
    // two pointer parameters(location and size).
    // Other parameters will pass as a single pointer
    return std::apply(f,parameters);
}

int main()
{
    double someArray[2] = {1, 4};
    double result = fortranCall(fFortran, 4, 5, someArray);

    double some_other_Array[] = {6,7,8,9,10};
    auto result2 = fortranCall(fFortranTwoArrays, someArray, some_other_Array);
}

एसटीडी :: लागू सी ++ 17 है। यदि आप इसे C++14 में काम करना चाहते हैं, तो https से उदाहरण कार्यान्वयन का उपयोग करें: //en.cppreference.com/w/cpp/utility/apply

namespace detail {
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>)
{
    return std::invoke(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))...);
}
}  // namespace detail

template <class F, class Tuple>
constexpr decltype(auto) apply(F&& f, Tuple&& t)
{
    return detail::apply_impl(
        std::forward<F>(f), std::forward<Tuple>(t),
        std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
}

और मार्टिन मोइन द्वारा बैकपोर्ट से इनवोक का उपयोग करें (https://github.com/martinmoene/invoke-lite< /ए>)

3
StefKKK 25 अप्रैल 2019, 13:44