我知道这个问题很老了,但它仍然是谷歌的第一个结果。而且由于接受答案中的第二个解决方案不像 cmets 中提到的那样工作,这里是 C++17 的一个很好的解决方案,包括 main 中的一个示例:
#include <tuple>
#include <type_traits>
//#define ALT2
#ifndef ALT2
template<typename T, std::size_t i = 0, std::size_t j = std::tuple_size<T>::value>
struct tuple_compare {
static bool
one_equal(T const& lhs, T const& rhs) {
if constexpr(i == j) return false;
else {
return (std::get<i>(lhs) == std::get<i>(rhs) ||
tuple_compare<T, i + 1, j>::one_equal(lhs, rhs));
}
}
};
#endif
template<typename... Conts>
struct container_ref_tuple {
static auto constexpr get_begin{[](auto&&... args){return std::make_tuple(begin(args)...);}};
typename std::invoke_result<decltype(&std::forward_as_tuple<Conts...>), Conts&&...>::type m_refs;
struct iterator {
typename std::invoke_result<decltype(get_begin), Conts&&...>::type m_iterators;
decltype(auto)
operator++() {
apply([](auto&... args) {((++args), ...);}, m_iterators);
return (*this);
}
#ifndef ALT2
//Alternative 1(safe)
//will stop when it reaches the end of the shortest container
auto
operator!=(iterator const& rhs) const {
return !tuple_compare<decltype(m_iterators)>::one_equal(m_iterators, rhs.m_iterators);
}
#else
//Alternative 2 (probably faster, but unsafe):
//use only, if first container is shortest
auto
operator!=(iterator const& rhs) const {
return std::get<0>(m_iterators) != std::get<0>(rhs.m_iterators);
}
#endif
auto
operator*() const {
return apply([](auto&... args){return std::forward_as_tuple(*args...);}, m_iterators);
}
};
auto
begin() const {
return iterator{apply(get_begin, m_refs)};
}
#ifndef ALT2
//Alternative 1(safe)
//will stop when it reaches the end of the shortest container
static auto constexpr get_end{[](auto&&... args){return std::make_tuple(end(args)...);}};
auto
end() const {
return iterator{apply(get_end, m_refs)};
}
#else
//Alternative 2 (probably faster, but unsafe):
//use only, if first container is shortest
auto
end() const {
iterator ret;
std::get<0>(ret.m_iterators) = std::end(std::get<0>(m_refs));
return ret;
}
#endif
};
template<typename... Conts>
auto
make_container_ref_tuple(Conts&&... conts) {
return container_ref_tuple<Conts...>{std::forward_as_tuple(conts...)};
}
#include <array>
#include <iostream>
#include <list>
#include <vector>
int
main(int argc, char** argv) {
std::array integers{1, 2, 3, 4, 5, 6, 7, 8};
std::list prime{2, 3, 5, 7, 11, 13, 17, 19, 23};
std::vector chars{'a', 'b', 'c'};
for(auto&& [i, p, c] : make_container_ref_tuple(integers, prime, chars)) {
std::cout << i << ' ' << p << ' ' << c << '\n';
std::swap(i, p);
++c;
}
std::cout << "New: \n";
for(auto&& [i, p, c] : make_container_ref_tuple(integers, prime, chars)) {
std::cout << i << ' ' << p << ' ' << c << '\n';
}
return 0;
}