【问题标题】:C++ virtual method that takes STL-style iterators采用 STL 风格迭代器的 C++ 虚方法
【发布时间】:2012-05-25 23:07:55
【问题描述】:

我想要一个接口 ModelGenerator,它有一个方法 generate(),它接受一个可迭代的证据列表并创建一个模型。使用 STL 伪鸭类型迭代器习语...

template<class Model>
class ModelGenerator {
  public:
    template<class Iterator>
    virtual bool generate(Iterator begin, Iterator end, Model& model) = 0;
};

但是虚函数不能被模板化。所以我必须对整个班级进行模板化:

template<class Model, class Iterator>
class ModelGenerator {
  public:
    virtual bool generate(Iterator begin, Iterator end, Model& model) = 0;
};

理想情况下我想做的是这样的......

template<class Model, class Evidence>
class ModelGenerator {
  public:
    virtual bool generate(iterator<Evidence>& begin,
                          iterator<Evidence>& end,
                          Model& model) = 0;
};

但是没有迭代器继承的接口。 (std::iterator 类只包含一堆 typedef,没有方法。)

我能想到的唯一方法是给 ModelGenerator 一个方法 addEvidence(),它在调用 generate() 之前将它们一个一个添加,但是我必须给 ModelGenerator 状态,这有点痛苦。

如何编写一个接受任何 STL 容器的虚拟方法?

【问题讨论】:

  • 您应该考虑从虚函数中分解出所有迭代器操作。模板化函数可能会生成 std::vector&lt; Evidence * &gt; 并将其传递给 virtual 函数。这种包装器的性能成本和编程工作量可能低于any_iterator/any_range

标签: c++ templates stl iterator virtual


【解决方案1】:

您似乎需要any_iterator。这是一个执行类型擦除以将您与实际的迭代器实现隔离开来的迭代器。

Adobe 有一个any_iterator 的实现: http://stlab.adobe.com/classadobe_1_1any__iterator.html

Boost 有一个any_range 的实现: http://www.boost.org/doc/libs/1_49_0/libs/range/doc/html/range/reference/ranges/any_range.html

【讨论】:

  • 请记住,any_iterator 的实现速度很慢,因此请仅在必要时使用它们。
  • Boost.Range 中有any_range
  • @funkybluecoffee:Boost offers an implementation.
  • 我不知道 Boost 的 any_range,它肯定比使用两个 any_iterators 好!
  • @abarnert:any_iterator 的问题在于,每次推进、比较、递增操作都涉及到 virtual 调用。所以开销相当大,值得一提。
【解决方案2】:

为此,您可以考虑使用模板特化而不是虚拟方法。据我了解,您有一个独特的 Evidence 类、许多不同的 Model 类,并且想要创建一个通用工厂以从一系列证据中生成选定的模型。

#include <vector>
#include <iostream>

struct Model1 { };
struct Model2 { };
struct Evidence { };

template<class Model>
struct ModelGenerator;

template<>
struct ModelGenerator<Model1>
{
    typedef Model1 model_type;

    template<class Iterator>
    model_type generate(Iterator begin, Iterator end)
    {
        std::cout << "Generate Model1\n";
        return model_type();
    }
};

template<>
struct ModelGenerator<Model2>
{
    typedef Model2 model_type;

    template<class Iterator>
    model_type generate(Iterator begin, Iterator end)
    {
        std::cout << "Generate Model2\n";
        return model_type();
    }
};

template<class Model, class Iterator>
Model make_model(Iterator begin, Iterator end)
{
    ModelGenerator<Model> gen;
    return gen.generate(begin, end);
}

你可以这样使用它:

int main()
{
    std::vector<Evidence> v;

    Model1 m1 = make_model<Model1>(v.begin(), v.end());
    Model2 m2 = make_model<Model2>(v.begin(), v.end());
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-17
    • 2011-06-22
    • 1970-01-01
    • 2011-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-12
    相关资源
    最近更新 更多