Суммируйте компоненты кортежа с помощью std :: get, std :: tuple_size, std :: tuple_element

У меня есть собственный класс с интерфейсом, похожим на кортеж. Поскольку я хочу, чтобы мой код был как можно более универсальным, я подумал, что было бы неплохо основывать свои алгоритмы на функциях std::get, std::tuple_size, std::tuple_element так что вы просто должны специализировать эти функции, чтобы использовать мои алгоритмы. Давайте назовем концепцию, которая требует этих специализаций функций Tuple,

Сейчас я пытаюсь подвести итог компонентов Tuple, Объявление функции должно быть примерно таким:

template <class Tuple>
int sum_components(const Tuple& t);

Я предполагаю, что здесь задействовано много шаблонных программ, но я просто не могу понять, как это сделать.

Для добавления я бы просто использовал перегрузку глобальной + operator,

Я использую c ++ 1z.

3

Решение

Это очень легко в .

template<class Tuple>
decltype(auto) sum_components(Tuple const& tuple) {
auto sum_them = [](auto const&... e)->decltype(auto) {
return (e+...);
};
return std::apply( sum_them, tuple );
};

или же (...+e) для противоположного направления сгиба.

В предыдущих версиях правильным подходом было бы написать свой собственный apply вместо того, чтобы писать сделанную на заказ реализацию. Когда ваш компилятор обновится, вы сможете удалить код.

В , Я мог бы сделать это:

// namespace for utility code:
namespace utility {
template<std::size_t...Is>
auto index_over( std::index_sequence<Is...> ) {
return [](auto&&f)->decltype(auto){
return decltype(f)(f)( std::integral_constant<std::size_t,Is>{}... );
};
}
template<std::size_t N>
auto index_upto() {
return index_over( std::make_index_sequence<N>{} );
}
}
// namespace for semantic-equivalent replacements of `std` code:
namespace notstd {
template<class F, class Tuple>
decltype(auto) apply( F&& f, Tuple&& tuple ) {
using dTuple = std::decay_t<Tuple>;
auto index = ::utility::index_upto< std::tuple_size<dTuple>{} >();
return index( [&](auto...Is)->decltype(auto){
auto target=std::ref(f);
return target( std::get<Is>( std::forward<Tuple>(tuple) )... );
} );
}
}

что довольно близко к std::apply в . (Я ругаю std::ref получить INVOKE семантика). (Он не работает идеально с вызовами rvalue, но это очень сложный случай).

В , Я бы посоветовал обновить ваш компилятор на этом этапе. В Я бы посоветовал улучшить вашу работу на этом этапе.


Все вышеперечисленное делает правую или левую складки. В некоторых случаях двоичное дерево может быть лучше. Это сложнее.

Если твой + делает шаблоны выражений, приведенный выше код не будет работать хорошо из-за проблем со временем жизни. Возможно, вам придется добавить другой тип шаблона для «after, cast-to», чтобы в некоторых случаях вычислять временное дерево выражений.

10

Другие решения

С C ++ 1z это довольно просто сложить выражения. Сначала отправьте кортеж на _impl функции и предоставьте ей индексную последовательность для доступа ко всем элементам кортежа, затем суммируйте:

template<typename T, size_t... Is>
auto sum_components_impl(T const& t, std::index_sequence<Is...>)
{
return (std::get<Is>(t) + ...);
}

template <class Tuple>
int sum_components(const Tuple& t)
{
constexpr auto size = std::tuple_size<Tuple>{};
return sum_components_impl(t, std::make_index_sequence<size>{});
}

демонстрация


Подход C ++ 14 состоит в том, чтобы рекурсивно суммировать пакет с переменными значениями:

int sum()
{
return 0;
}

template<typename T, typename... Us>
auto sum(T&& t, Us&&... us)
{
return std::forward<T>(t) + sum(std::forward<Us>(us)...);
}

template<typename T, size_t... Is>
auto sum_components_impl(T const& t, std::index_sequence<Is...>)
{
return sum(std::get<Is>(t)...);
}

template <class Tuple>
int sum_components(const Tuple& t)
{
constexpr auto size = std::tuple_size<Tuple>{};
return sum_components_impl(t, std::make_index_sequence<size>{});
}

демонстрация

Подход C ++ 11 был бы подходом C ++ 14 с пользовательской реализацией index_sequence, Например из Вот.


Как отметил @ildjarn в комментариях, оба приведенных выше примера используют правые сгибы, в то время как многие программисты ожидают левых сгибов в своем коде. Версия C ++ 1z тривиально изменчива:

template<typename T, size_t... Is>
auto sum_components_impl(T const& t, std::index_sequence<Is...>)
{
return (... + std::get<Is>(t));
}

демонстрация

И C ++ 14 не намного хуже, но есть больше изменений:

template<typename T, typename... Us>
auto sum(T&& t, Us&&... us)
{
return sum(std::forward<Us>(us)...) + std::forward<T>(t);
}

template<typename T, size_t... Is>
auto sum_components_impl(T const& t, std::index_sequence<Is...>)
{
constexpr auto last_index = sizeof...(Is) - 1;
return sum(std::get<last_index - Is>(t)...);
}

демонстрация

5

По вопросам рекламы [email protected]