Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
291 views
in Technique[技术] by (71.8m points)

c++ - Sum the components of a tuple up by using std::get, std::tuple_size, std::tuple_element

I've got a custom class that has a tuple-like interface. Because I want my code to be as generic as possible, I thought that it would be a good idea to base my algorithms on the functions std::get, std::tuple_size, std::tuple_element so you just have to specialize these functions to use my algorithms. Let's call the concept that requires these function specializations Tuple.

Now I am trying to sum up the components of a Tuple. The function declaration should be something like this:

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

I guess that there is a lot of template programming involved but I just can't figure out how to do it.

For the addition I would just use an overload of the global + operator.

I am using c++1z.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is very easy in .

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 , 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 . (I abuse std::ref to get INVOKE semantics). (It does not work perfectly with rvalue invokers, but that is very corner case).

In , I would advise upgrading your compiler at this point. In 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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...