C ++의 Boost.MultiArray에 대한 합계 함수

Oct 29 2020

이것은 C ++의 임의 중첩 벡터 구현을 위한 합계 함수 및 C ++의 다양한 유형 임의 중첩 반복 가능 구현 을 위한 합계 함수에 대한 후속 질문입니다 . Boost Multidimensional Array Library에recursive_sum 대한 기능 을 구현하려고합니다 . 이 함수 의 목적은 입력 데이터의 각 요소를 합산하는 것 입니다. 여기서 재귀 구조는 이전 구현 및 다른 유형의 중첩 반복 가능과 유사합니다 . 또한, I는 다음과 같은 여러 종류가 있다는 것을 발견 , 및 Boost.MultiArray 라이브러리입니다. 아래와 같이 여러 오버로드 기능을 사용하여 이러한 유형을 처리하려고합니다.recursive_sumboost::multi_arraystd::vectorboost::multi_arrayboost::detail::multi_array::sub_arrayboost::detail::multi_array::const_sub_array

template<class T> requires is_summable<T>
auto recursive_sum(const T& input)
{
    return input;
}

//  Deal with the boost::multi_array case
template<class T, std::size_t Dims> requires is_summable<T>
auto recursive_sum(const boost::detail::multi_array::const_sub_array<T, Dims>& input)
{
    T sum_output{};
    for (typename boost::multi_array<T, Dims>::index i = 0; i < input.shape()[0]; i++)
    {
        sum_output += recursive_sum(input[i]);
    }
    return sum_output;
}

//  Deal with the boost::multi_array case
template<class T, std::size_t Dims> requires is_summable<T>
auto recursive_sum(const boost::detail::multi_array::sub_array<T, Dims>& input)
{
    T sum_output{};
    for (typename boost::multi_array<T, Dims>::index i = 0; i < input.shape()[0]; i++)
    {
        sum_output += recursive_sum(input[i]);
    }
    return sum_output;
}

//  Deal with the boost::multi_array case
template<class T, std::size_t Dims> requires is_summable<T>
auto recursive_sum(boost::multi_array<T, Dims>& input)
{
    T sum_output{};
    for (typename boost::multi_array<T, Dims>::index i = 0; i < input.shape()[0]; i++)
    {
        sum_output += recursive_sum(input[i]);
    }
    return sum_output;
}

사용 된 is_summable개념 :

template<typename T>
concept is_summable = requires(T x) { x + x; };

이 recursive_sum기능에 대한 테스트 :

int main()
{
    // Create a 3D array that is 3 x 4 x 2
    typedef boost::multi_array<double, 3> array_type;
    typedef array_type::index index;
    array_type A(boost::extents[3][4][2]);

    // Assign values to the elements
    int values = 0;
    for (index i = 0; i != 3; ++i)
        for (index j = 0; j != 4; ++j)
            for (index k = 0; k != 2; ++k)
                A[i][j][k] = values++;
    
    auto recursive_sum_output = recursive_sum(A);
    std::cout << "recursive_sum_output: " << recursive_sum_output;
    
    return 0;
}

모든 제안을 환영합니다.

  • 어떤 질문에 대한 후속 조치입니까?

    C ++ 및 C ++에서 임의 중첩 벡터 구현을위한 합산 함수

    C ++에서 다양한 유형의 임의 중첩 반복 가능 구현을위한 합계 함수

  • 지난 질문 이후 코드에서 어떤 변화가 있었습니까?

    이전 질문은 .NET Framework와 같은 C ++ STL의 공통 컨테이너에 중점을 둡니다 std::vector. 이 질문의 주요 아이디어는 처리 할 수있는 또 다른 유형 합계 함수를 구현하려는 것입니다 boost::multi_array.

  • 새로운 리뷰가 요청되는 이유는 무엇입니까?

    I있다 Boost.MultiArray 라이브러리 어레이 구조의 세 가지 유형 인 것으로 boost::multi_array, boost::detail::multi_array::sub_array및 boost::detail::multi_array::const_sub_array. 이러한 서로 다른 유형 클래스를 처리하기 위해 recursive_sum각 유형을 개별적으로 처리하는 세 가지 오버로드 함수 가 있습니다. 이러한 과부하 기능을 단순화하는 더 좋은 방법이 있는지 잘 모르겠습니다. 또한이 코드에 대해 개선이 가능한 경우 알려 주시기 바랍니다.

답변

3 G.Sliepen Oct 29 2020 at 23:59

재귀 구현 std::reduce()

당신은 특별한 경우에 필요가 없습니다 boost::multi_array그 종류가 이미 STL 컨테이너처럼 행동으로 (그들이 제공 및 관련 유형 begin()및 end()예를 들어). 그러나 주요 문제는 반환 유형을 추론하는 방법입니다 recursive_sum(). 그들은 추론하기 때문에 귀하의 기능이 제대로 작동 TA로부터 boost::multi_array<T, Dims>,하지만 그들은 정말합니까? 의 차원 에 대해 recursive_sum()반복 되지만 실제로 중첩 된 s를 처리하지 않습니다 . 예를 들면 다음과 같습니다.multi_arraymulti_array

boost::multi_array<boost::multi_array<double, 2>, 3> array;

그 이유는 상기의 경우에, 호출 인 것으로 recursive_sum(array)추론 할 T것으로 boost::multi_array<double, 2>대신들 double.

이 문제를 해결하기 위해 내가 std::reduce()하는 일을하고 합계에 대한 초기 값을 요구하여 문제를 회피 할 것 입니다. 이 초기 값의 유형도 반환 유형이됩니다. 예를 들면 :

template<class T, class ValueType, class Function = std::plus<ValueType>>
auto recursive_reduce(const T& input, ValueType init, const Function& f)
{
    return f(init, input);
}

template<class Container, class ValueType, class Function = std::plus<ValueType>>
requires is_iterable<Container>
auto recursive_reduce(const Container& input, ValueType init, const Function& f = std::plus<ValueType>())
{
    for (const auto &element: input) {
        auto result = recursive_reduce(element, ValueType{}, f);
        init = f(init, result);
    }

    return init;
}

그런 다음 다음과 같이 호출 할 수 있습니다.

boost::multi_array<...> array(...);
std::cout << recursive_reduce(array, 0.0) << "\n";

가장 안쪽에있는 값 유형을 찾기 위해 템플릿을 작성하여에서 템플릿 매개 변수 ValueType에 대한 기본값으로 recursive_reduce()사용할 수 {}있으며에서 기본값으로 사용할 수 있으며 다음과 같이 init작성할 수 있습니다.

std::cout << recursive_reduce(array) << "\n";