【问题标题】:Template Member Function to Write to Output Iterator要写入输出迭代器的模板成员函数
【发布时间】:2012-06-14 15:09:25
【问题描述】:

我认为我会很聪明并创建接受输出迭代器的成员函数。这样,我可以避免返回集合或通过引用获取集合。例如:

template <typename TOutIterator>
void getHeaderNames(TOutIterator destination);

template <typename TOutIterator>
void getHeaderValues(std::string const& name, TOutIterator destination);

这些函数会将其结果写入传入的任何迭代器。这样,我不必担心我是写入集合、向量还是 ostream。

现在我感觉没那么聪明了。我想让这些函数虚拟化,这样我就可以在测试中删除实现。不幸的是,模板成员函数不能是虚拟的,这是有道理的。

有没有办法让这些函数保持通用(写入任何东西)并允许它们同时是虚拟的?我想避免将所有内容都写入向量,然后转身将其写入标准输出或其他任何内容。

如果我需要更清楚地解释我的情况,请告诉我。

【问题讨论】:

    标签: c++ templates iterator virtual member-functions


    【解决方案1】:

    您可以使用type erasure 来操作多态迭代器,例如any_iterator proposed by Thomas Becker(以及后来的implemented in Boost.Range)。你最终会得到类似的东西:

    typedef any_iterator<
      std::string, // Value
      Writable,    // Access
      Forward,     // Traversal
    > StringOutputIterator; // can represent any output iterator accepting strings
    
    virtual void getHeaders(StringOutputIterator destination);
    

    类型擦除的想法是为一组原本不相关的类型(由于使用模板而在 C++ 中经常发生)拥有一个公共基类。例如,std::function 通过允许以类似方式对函数指针、仿函数或 lambda 进行操作,将此习惯用法应用于可调用对象。

    【讨论】:

    • 在 Boost 中有一个特定的 header 是 any_iterator 所在的位置吗?
    • @TravisParks:检查答案中的链接。但是,Boost.Range 中的any_iterator 被用作any_range 的实现细节,我不确定它是否适合库用户使用。无论如何,您都可以尝试使用它,或者提出您自己的版本(从 Becker 和 Grove 的实现中汲取灵感)。
    • 我有另一个想法:我可以创建一个具有开始/结束方法的标头集合类。这些方法仍然需要返回一个不公开实现细节的迭代器类型。 any_iterator 的间接性要少得多。
    【解决方案2】:

    保持它们通用的一种方法,我通常在实践中看到这一点,是两个重载流输出运算符(如果有意义的话)或采用std::ostream&amp;

    当然,这取决于您的具体情况:您是否正在编写迭代器更有意义的算法?还是只是想转储对象的内容?

    【讨论】:

    • 在我的对象内部,有一个 map> 表示从 HTTP 请求返回的标头键/值对。我希望允许在不暴露底层数据结构的情况下迭代键和每个键的值(例如,多映射也可以工作)。
    【解决方案3】:

    我遇到了类似的问题,我不想将 Boost 添加到我的项目中......所以我决定根本不使用迭代器。

    我最终改用std::function

    void getHeaderNames(std::function<void(std::string)> destination);
    
    void getHeaderValues(std::string const& name, std::function<void(std::string)> destination);
    

    然后,我提供一个执行 push_back 的 lambda,而不是 std::back_inserter

    std::vector<std::string> v;
    getHeaderNames([&](auto name) { v.push_back(std::move(name)); });
    

    【讨论】:

      猜你喜欢
      • 2012-03-19
      • 1970-01-01
      • 2020-03-10
      • 2011-07-20
      • 2019-02-27
      • 2012-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多