>

종종 C ++ 코드에서 일부 포트란 루틴을 호출해야합니다. 필자의 경우 C 헤더는 항상 사용할 수 있으며

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

내 질문은 : 일반적인 C ++ 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);

올바른 솔루션에는 매개 변수 팩이 포함되어 있다고 생각하지만 하나를 반복하고 필요한 경우 참조하는 방법을 알 수 없습니다.

  • 답변 # 1

    이 답변을 위해 다음과 같은 가정을합니다 :

    FORTRAN 함수에 대한 매개 변수는 모두 포인터로 전달됩니다.

    포인터 주소는 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);
    }
    
    
    <시간>

    std :: apply는 C ++ 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>{});
    }
    
    

    Martin Moene (https://github.com/martinmoene/invoke-lite)의 백 포트에서 호출 사용

  • 이전 sql server - Docker 컨테이너에서 SSMS를 Linux SqlServer에 연결하는 방법은 무엇입니까?
  • 다음 android - AsyncTask를 사용하여 XML을로드하는 동안 오류가 발생 함