Funkcja sumowania dla Boost.MultiArray w C ++
To jest pytanie uzupełniające dla funkcji sumowania dla implementacji arbitralnego zagnieżdżonego wektora w C ++ i funkcji sumowania dla różnych typów zagnieżdżonych implementacji w języku C ++ . Próbuję zaimplementować recursive_sumfunkcję dla Boost Multidimensional Array Library . Celem tej recursive_sumfunkcji jest podsumowanie każdego elementu w boost::multi_arraydanych wejściowych . Struktura rekurencyjna w tym miejscu jest podobna do poprzedniej implementacji for std::vectori innego typu zagnieżdżonego iterowalnego. Co więcej, okazało się, że istnieje kilka rodzajów w tym boost::multi_array, boost::detail::multi_array::sub_arraya boost::detail::multi_array::const_sub_arrayw bibliotece Boost.MultiArray. Próbuję obsłużyć te typy z wieloma funkcjami przeciążenia, jak poniżej.
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;
}
Zastosowana is_summablekoncepcja:
template<typename T>
concept is_summable = requires(T x) { x + x; };
Test dla tej recursive_sumfunkcji:
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;
}
Wszelkie sugestie są mile widziane.
Które pytanie jest kontynuacją?
Funkcja sumowania dla implementacji dowolnego zagnieżdżonego wektora w C ++ i
Funkcja sumowania dla różnego typu, arbitralnie zagnieżdżonych, iterowalnych implementacji w C ++
Jakie zmiany wprowadzono w kodzie od ostatniego pytania?
Poprzednie pytanie dotyczy typowych kontenerów w języku C ++ STL, takich jak
std::vector. Główną ideą w tym pytaniu jest próba zaimplementowania innej funkcji sumowania, która może sobie poradzićboost::multi_array.Dlaczego prosi się o nową recenzję?
Okazało się, że istnieją trzy rodzaje konstrukcji tablicy w bibliotece Boost.MultiArray które są
boost::multi_array,boost::detail::multi_array::sub_arrayiboost::detail::multi_array::const_sub_array. Aby obsłużyć te różne klasy typów, istnieją trzy funkcje przeciążenia, którerecursive_sumobsługują każdy typ osobno. Nie jestem pewien, czy istnieje lepszy sposób na uproszczenie tych funkcji przeciążenia. Ponadto, jeśli jest możliwe ulepszenie tego kodu, daj mi znać.
Odpowiedzi
Zaimplementuj rekurencyjny std::reduce()
Nie powinieneś potrzebować specjalnych przypadków boost::multi_arrayi powiązanych typów, ponieważ te typy działają już jak kontenery STL (zapewniają begin()i end()na przykład). Główny problem polega jednak na tym, jak wydedukować typ zwracanego pliku recursive_sum(). Twoje funkcje wydają się działać, ponieważ wywnioskują Tz a boost::multi_array<T, Dims>, ale czy naprawdę? Twój recursive_sum()powtarza się w wymiarach a multi_array, ale w rzeczywistości nie obsługuje zagnieżdżonych multi_arrays, jak na przykład:
boost::multi_array<boost::multi_array<double, 2>, 3> array;
Powodem jest to, że w powyższym przypadku wywołanie recursive_sum(array)spowoduje, Tże będzie a boost::multi_array<double, 2>zamiast a double.
Aby rozwiązać ten problem, zrobiłbym to, co std::reduce()robi, i omijałby problem, wymagając podania początkowej wartości sumy. Typ tej wartości początkowej będzie również typem zwracanym. Na przykład:
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;
}
Następnie możesz to nazwać tak:
boost::multi_array<...> array(...);
std::cout << recursive_reduce(array, 0.0) << "\n";
Być może mógłbyś napisać jakiś szablon, aby znaleźć najbardziej wewnętrzny typ wartości, aby móc go użyć jako wartości domyślnej dla parametru szablonu ValueTypew recursive_reduce(), a następnie użyć {}jako wartości domyślnej dla initi móc pisać:
std::cout << recursive_reduce(array) << "\n";