能否从函数中根据条件返回不同容器的迭代器对?
可行方案:返回不同容器的迭代器对
一、直接可行,两种主流实现方式
1. C++17及以上:使用std::variant(推荐)
std::variant是标准库提供的类型安全联合体,可直接包装两种不同的迭代器对类型,返回值类型明确且无额外性能损耗。
代码示例:
#include <variant> #include <vector> #include <list> #include <utility> #include <iostream> // 定义示例容器类型 template<typename T> using C = std::vector<T>; template<typename T> using D = std::list<T>; template<typename T> auto get_iter_pair(bool use_container_c, C<T>& c, D<T>& d) { // 定义两种迭代器对类型的variant using CIterPair = std::pair<typename C<T>::iterator, typename C<T>::iterator>; using DIterPair = std::pair<typename D<T>::iterator, typename D<T>::iterator>; using IterPairVariant = std::variant<CIterPair, DIterPair>; return use_container_c ? IterPairVariant{std::make_pair(c.begin(), c.end())} : IterPairVariant{std::make_pair(d.begin(), d.end())}; } // 使用示例 int main() { C<int> vec = {1, 2, 3}; D<int> lst = {4, 5, 6}; // 获取vector的迭代器对并遍历 auto pair = get_iter_pair(true, vec, lst); std::visit([](auto&& p) { for (auto it = p.first; it != p.second; ++it) { std::cout << *it << " "; } std::cout << "\n"; }, pair); // 获取list的迭代器对并遍历 pair = get_iter_pair(false, vec, lst); std::visit([](auto&& p) { for (auto it = p.first; it != p.second; ++it) { std::cout << *it << " "; } std::cout << "\n"; }, pair); return 0; }
使用时通过std::visit分发处理两种迭代器类型,逻辑清晰且符合标准库规范。
2. 多态迭代器包装器(透明接口)
如果需要更接近普通迭代器的使用体验(无需std::visit),可实现一个多态包装器,封装不同类型的迭代器并提供统一接口。代价是虚函数调用的性能损耗和堆内存分配。
代码示例:
#include <vector> #include <list> #include <memory> #include <utility> #include <iostream> // 抽象迭代器基类 template<typename T> class AnyIterator { public: virtual ~AnyIterator() = default; virtual T& operator*() = 0; virtual const T& operator*() const = 0; virtual AnyIterator& operator++() = 0; virtual bool operator!=(const AnyIterator& other) const = 0; virtual std::unique_ptr<AnyIterator> clone() const = 0; }; // 具体迭代器包装类 template<typename Iter> class IteratorWrapper : public AnyIterator<typename std::iterator_traits<Iter>::value_type> { private: Iter m_iter; public: using ValueType = typename std::iterator_traits<Iter>::value_type; explicit IteratorWrapper(Iter iter) : m_iter(std::move(iter)) {} ValueType& operator*() override { return *m_iter; } const ValueType& operator*() const override { return *m_iter; } IteratorWrapper& operator++() override { ++m_iter; return *this; } bool operator!=(const AnyIterator<ValueType>& other) const override { const auto* wrapper = dynamic_cast<const IteratorWrapper*>(&other); return wrapper ? (m_iter != wrapper->m_iter) : false; } std::unique_ptr<AnyIterator<ValueType>> clone() const override { return std::make_unique<IteratorWrapper>(m_iter); } }; // 迭代器对的包装结构,支持范围for template<typename T> struct AnyIterPair { std::unique_ptr<AnyIterator<T>> first; std::unique_ptr<AnyIterator<T>> last; struct RangeIter { std::unique_ptr<AnyIterator<T>> current; std::unique_ptr<AnyIterator<T>> end; bool operator!=(const RangeIter& other) const { return *current != *other.end; } T& operator*() { return **current; } RangeIter& operator++() { ++*current; return *this; } }; RangeIter begin() const { return {first->clone(), last->clone()}; } RangeIter end() const { return {last->clone(), last->clone()}; } }; // 定义示例容器类型 template<typename T> using C = std::vector<T>; template<typename T> using D = std::list<T>; template<typename T> AnyIterPair<T> get_iter_pair(bool use_container_c, C<T>& c, D<T>& d) { if (use_container_c) { return { std::make_unique<IteratorWrapper<typename C<T>::iterator>>(c.begin()), std::make_unique<IteratorWrapper<typename C<T>::iterator>>(c.end()) }; } else { return { std::make_unique<IteratorWrapper<typename D<T>::iterator>>(d.begin()), std::make_unique<IteratorWrapper<typename D<T>::iterator>>(d.end()) }; } } // 使用示例 int main() { C<int> vec = {1, 2, 3}; D<int> lst = {4, 5, 6}; auto pair = get_iter_pair(true, vec, lst); for (int val : pair) { std::cout << val << " "; } std::cout << "\n"; pair = get_iter_pair(false, vec, lst); for (int val : pair) { std::cout << val << " "; } std::cout << "\n"; return 0; }
这种方式可像普通迭代器对一样直接用于范围for循环,对调用者更透明。
二、补充说明
- 如果两个容器都是连续内存类型(如
vector、array),C++20的std::span也是可选方案,但它仅支持随机访问迭代器,无法适配list这类非连续容器。 - 优先选择
std::variant方案,它属于标准库、性能更优且类型安全;多态包装器适合需要完全透明迭代器接口的场景。
内容的提问来源于stack exchange,提问作者0xbadf00d
相关产品推荐
相关产品推荐

