C++如何包装vector<T>迭代器提取结构体指定成员计算平均值
方案1:C++20 ranges 迭代器适配器(最简洁)
无需修改现有mean函数,直接用标准库提供的视图转换生成自动提取a成员的迭代范围即可:
#include <ranges> // 调用逻辑 auto a_range = v | std::views::transform(&T::a); double a_mean = mean(a_range.begin(), a_range.end());
该方案零额外编码,原生满足「迭代时自动提取指定成员」的需求。
方案2:自定义轻量转换迭代器(兼容C++11及以上)
如果编译器不支持C++20,可以自己实现通用的成员提取迭代器包装:
#include <iterator> template <typename OrigIter, typename MemberType> struct MemExtractIter { OrigIter orig; MemberType T::*mem; using value_type = MemberType; using difference_type = typename OrigIter::difference_type; using pointer = MemberType*; using reference = MemberType&; using iterator_category = std::input_iterator_tag; MemExtractIter(OrigIter o, MemberType T::*m) : orig(o), mem(m) {} reference operator*() const { return (*orig).*mem; } MemExtractIter& operator++() { ++orig; return *this; } MemExtractIter operator++(int) { auto tmp = *this; ++orig; return tmp; } bool operator==(const MemExtractIter& other) const { return orig == other.orig; } bool operator!=(const MemExtractIter& other) const { return orig != other.orig; } }; // 辅助构造函数,自动推导模板参数 template <typename OrigIter, typename MemberType> MemExtractIter<OrigIter, MemberType> make_mem_extract_iter(OrigIter o, MemberType T::*m) { return MemExtractIter<OrigIter, MemberType>(o, m); }
调用时直接传入包装后的迭代器即可:
double a_mean = mean( make_mem_extract_iter(v.begin(), &T::a), make_mem_extract_iter(v.end(), &T::a) );
该包装器是通用实现,要提取b成员仅需把&T::a替换为&T::b即可。
方案3:给mean函数增加投影参数(扩展性最强)
如果可以微调原有mean函数,增加投影参数后适配性会更强,支持所有自定义取值逻辑:
#include <functional> template<typename I, typename Proj = std::identity> double mean(I begin, I end, Proj proj = {}) { double s = 0; size_t n = 0; while(begin != end) { s += std::invoke(proj, *begin++); ++n; } return n == 0 ? 0 : s / n; // 额外补充空容器边界处理 }
调用时直接传入成员指针作为投影:
double a_mean = mean(v.begin(), v.end(), &T::a);
该方案兼容C++17及以上,也支持更复杂的计算逻辑,比如要计算a+b的平均值,仅需传入lambda:mean(v.begin(), v.end(), [](const T& t){ return t.a + t.b; })。
内容的提问来源于stack exchange,提问作者Ordev Agens
相关产品推荐
相关产品推荐

