This is very easy in c++17.
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 );
};
or (...+e)
for the opposite fold direction.
In previous versions, the right approach would be to write your own apply
rather than writing a bespoke implementation. When your compiler updates, you can then delete code.
In c++14, I might do this:
// 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) )... );
} );
}
}
which is pretty close to std::apply
in c++14. (I abuse std::ref
to get INVOKE
semantics). (It does not work perfectly with rvalue invokers, but that is very corner case).
In c++11, I would advise upgrading your compiler at this point. In c++03 I'd advise upgrading your job at this point.
All of the above do right or left folds. In some cases, a binary tree fold might be better. This is trickier.
If your +
does expression templates, the above code won't work well due to lifetime issues. You may have to add another template type for "afterwards, cast-to" to cause the temporary expression tree to evaluate in some cases.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…