如何声明接收整数范围的多态接口函数?避免额外内存分配
问题解决方案:在多态接口中传递std::ranges::view(无额外内存分配)
你的核心问题是C++不允许虚函数使用模板参数(包括auto缩写的模板参数),但又需要通过多态接口传递任意std::ranges::input_range<int>类型的view,同时避免内存分配。以下是两种可行的解决方案:
方案一:回调式处理(推荐)
将接口从接收整个range改为处理单个元素,由调用方负责遍历view。这种方式无需复杂的类型擦除,实现简单且无额外内存分配。
修改后的完整代码:
#include <ranges> #include <algorithm> #include <iostream> #include <memory> #include <vector> // 模拟NetworkAdapter类 class NetworkAdapter { public: NetworkAdapter& operator<<(int value) { // 实现网络发送逻辑 return *this; } }; class IGetRange{ public: virtual ~IGetRange() = default; // 处理单个int元素的虚函数 virtual void handleInt(int value) = 0; // 可选:处理前后的初始化/收尾逻辑 virtual void startProcessing() {} virtual void finishProcessing() {} }; class PrintRange : public IGetRange{ void handleInt(int value) override { std::cout << value << ' '; } void finishProcessing() override { std::cout << '\n'; } }; class SendOverNetworkRange : public IGetRange{ NetworkAdapter networkAdapter; void handleInt(int value) override { networkAdapter << value; } }; class Caller { std::vector<std::pair<int, std::string>> pairs = {{1,"one"}, {2, "two"}}; std::unique_ptr<IGetRange> rngProcessor = std::make_unique<SendOverNetworkRange>(); public: void sendKeys() { auto passView = pairs | std::views::filter([](const auto& p) { return p.first > 0; }) | std::views::transform([](auto&& p) { return p.first; }); rngProcessor->startProcessing(); // 调用方遍历view,逐个传递元素给接口 for (int val : passView) { rngProcessor->handleInt(val); } rngProcessor->finishProcessing(); } };
优点
- 实现逻辑简单,无需处理range的类型擦除
- 完全无额外内存分配,直接复用原view的元素
- 接口职责清晰,派生类只需关注单个元素的处理逻辑
方案二:类型擦除的Range包装器
如果必须保持“传递整个range给接口”的语义(比如派生类需要利用range的批量处理特性),可以实现一个类型擦除的包装类,将任意满足std::ranges::input_range<int>的对象包装成统一类型,用于虚函数参数。
完整实现代码:
#include <ranges> #include <algorithm> #include <iostream> #include <memory> #include <vector> #include <concepts> // 模拟NetworkAdapter类 class NetworkAdapter { public: struct iterator { using value_type = int; using iterator_category = std::output_iterator_tag; iterator& operator*() { return *this; } iterator& operator++() { return *this; } iterator operator++(int) { return *this; } void operator=(int val) { // 实现网络发送逻辑 } }; iterator begin() { return {}; } iterator end() { return {}; } }; // 类型擦除的int输入range包装器 class AnyIntInputRange { private: // 迭代器概念基类,封装核心操作 struct IterConcept { virtual ~IterConcept() = default; virtual int& deref() = 0; virtual void inc() = 0; virtual bool equals(const IterConcept* other) const = 0; virtual std::unique_ptr<IterConcept> clone() const = 0; }; // 针对具体迭代器类型的实现 template<std::input_iterator Iter> struct IterModel : IterConcept { Iter iter; IterModel(Iter i) : iter(std::move(i)) {} int& deref() override { return *iter; } void inc() override { ++iter; } bool equals(const IterConcept* other) const override { if (const auto* m = dynamic_cast<const IterModel*>(other)) { return iter == m->iter; } return false; } std::unique_ptr<IterConcept> clone() const override { return std::make_unique<IterModel>(iter); } }; // 对外暴露的迭代器类 class Iter { std::unique_ptr<IterConcept> impl; public: Iter(std::unique_ptr<IterConcept> p) : impl(std::move(p)) {} Iter(const Iter& other) : impl(other.impl->clone()) {} Iter& operator=(const Iter& other) { impl = other.impl->clone(); return *this; } Iter(Iter&&) = default; Iter& operator=(Iter&&) = default; int& operator*() { return impl->deref(); } Iter& operator++() { impl->inc(); return *this; } bool operator==(const Iter& other) const { return impl->equals(other.impl.get()); } }; std::unique_ptr<IterConcept> m_begin; std::unique_ptr<IterConcept> m_end; public: // 构造函数:接受任意input_range<int> template<std::ranges::input_range R> requires std::same_as<std::ranges::range_value_t<R>, int> AnyIntInputRange(R&& r) : m_begin(std::make_unique<IterModel<std::ranges::iterator_t<R>>>(std::ranges::begin(r))), m_end(std::make_unique<IterModel<std::ranges::iterator_t<R>>>(std::ranges::end(r))) {} Iter begin() const { return Iter(m_begin->clone()); } Iter end() const { return Iter(m_end->clone()); } }; // 多态接口 class IGetRange{ public: virtual ~IGetRange() = default; virtual void doSomethingWithInts(AnyIntInputRange intsView) = 0; }; class PrintRange : public IGetRange{ void doSomethingWithInts(AnyIntInputRange intsView) override { std::ranges::copy(intsView, std::ostream_iterator<int>(std::cout, " ")); std::cout << '\n'; } }; class SendOverNetworkRange : public IGetRange{ NetworkAdapter networkAdapter; void doSomethingWithInts(AnyIntInputRange intsView) override { std::ranges::copy(intsView, networkAdapter.begin()); } }; class Caller { std::vector<std::pair<int, std::string>> pairs = {{1,"one"}, {2, "two"}}; std::unique_ptr<IGetRange> rngProcessor = std::make_unique<SendOverNetworkRange>(); public: void sendKeys() { auto passView = pairs | std::views::filter([](const auto& p) { return p.first > 0; }) | std::views::transform([](auto&& p) { return p.first; }); rngProcessor->doSomethingWithInts(passView); } };
优点
- 保持了原接口的语义,派生类可以直接处理整个range
- 支持任意满足条件的input_range类型,无需修改接口
缺点
- 实现复杂,需要手动处理迭代器的类型擦除逻辑
- 遍历range时会有轻微的性能开销(迭代器的clone操作涉及堆内存分配)
内容的提问来源于stack exchange,提问作者A-_-S
相关产品推荐
相关产品推荐

