这是我的元组 foreach/transformation 函数:
#include <cstddef>
#include <tuple>
#include <type_traits>
template<size_t N>
struct tuple_foreach_impl {
template<typename T, typename C>
static inline auto call(T&& t, C&& c)
-> decltype(::std::tuple_cat(
tuple_foreach_impl<N-1>::call(
::std::forward<T>(t), ::std::forward<C>(c)
),
::std::make_tuple(c(::std::get<N-1>(::std::forward<T>(t))))
))
{
return ::std::tuple_cat(
tuple_foreach_impl<N-1>::call(
::std::forward<T>(t), ::std::forward<C>(c)
),
::std::make_tuple(c(::std::get<N-1>(::std::forward<T>(t))))
);
}
};
template<>
struct tuple_foreach_impl<0> {
template<typename T, typename C>
static inline ::std::tuple<> call(T&&, C&&) { return ::std::tuple<>(); }
};
template<typename T, typename C>
auto tuple_foreach(T&& t, C&& c)
-> decltype(tuple_foreach_impl<
::std::tuple_size<typename ::std::decay<T>::type
>::value>::call(std::forward<T>(t), ::std::forward<C>(c)))
{
return tuple_foreach_impl<
::std::tuple_size<typename ::std::decay<T>::type>::value
>::call(::std::forward<T>(t), ::std::forward<C>(c));
}
示例用法使用以下实用程序允许将元组打印到 ostream:
#include <cstddef>
#include <ostream>
#include <tuple>
#include <type_traits>
template<size_t N>
struct tuple_print_impl {
template<typename S, typename T>
static inline void print(S& s, T&& t) {
tuple_print_impl<N-1>::print(s, ::std::forward<T>(t));
if (N > 1) { s << ',' << ' '; }
s << ::std::get<N-1>(::std::forward<T>(t));
}
};
template<>
struct tuple_print_impl<0> {
template<typename S, typename T>
static inline void print(S&, T&&) {}
};
template<typename S, typename T>
void tuple_print(S& s, T&& t) {
s << '(';
tuple_print_impl<
::std::tuple_size<typename ::std::decay<T>::type>::value
>::print(s, ::std::forward<T>(t));
s << ')';
}
template<typename C, typename... T>
::std::basic_ostream<C>& operator<<(
::std::basic_ostream<C>& s, ::std::tuple<T...> const& t
) {
tuple_print(s, t);
return s;
}
最后,这里是示例用法:
#include <iostream>
using namespace std;
struct inc {
template<typename T>
T operator()(T const& val) { return val+1; }
};
int main() {
// will print out "(7, 4.2, z)"
cout << tuple_foreach(make_tuple(6, 3.2, 'y'), inc()) << endl;
return 0;
}
请注意,可调用对象的构造是为了在需要时保持状态。例如,您可以使用以下内容查找元组中可以动态转换为 T 的最后一个对象:
template<typename T>
struct find_by_type {
find() : result(nullptr) {}
T* result;
template<typename U>
bool operator()(U& val) {
auto tmp = dynamic_cast<T*>(&val);
auto ret = tmp != nullptr;
if (ret) { result = tmp; }
return ret;
}
};
请注意,这样做的一个缺点是它要求可调用对象返回一个值。但是,重写它以检测给定输入类型的返回类型是否为 void,然后跳过结果元组的那个元素并不难。更简单的是,您可以完全删除返回值聚合的东西,只需将 foreach 调用用作元组修饰符。
编辑:
我刚刚意识到可以使用 foreach 函数轻松编写元组编写器(我的元组打印代码比 foreach 代码要长得多)。
template<typename T>
struct tuple_print {
print(T& s) : _first(true), _s(&s) {}
template<typename U>
bool operator()(U const& val) {
if (_first) { _first = false; } else { (*_s) << ',' << ' '; }
(*_s) << val;
return false;
}
private:
bool _first;
T* _s;
};
template<typename C, typename... T>
::std::basic_ostream<C> & operator<<(
::std::basic_ostream<C>& s, ::std::tuple<T...> const& t
) {
s << '(';
tuple_foreach(t, tuple_print< ::std::basic_ostream<C>>(s));
s << ')';
return s;
}