0

我正在用 C++ 设计一个从 HTML 页面中提取 URL 的类。我正在使用 Boost 的 Regex 库为我完成繁重的工作。我开始设计一个类,并意识到我不想束缚 URL 的存储方式。std::vector<Url>一种选择是通过引用接受 a并在其上调用 push_back 。我想避免强迫我班的消费者使用std::vector. 因此,我创建了一个带有目标迭代器的成员模板。它看起来像这样:

template <typename TForwardIterator, typename TOutputIterator>
TOutputIterator UrlExtractor::get_urls(
    TForwardIterator begin,
    TForwardIterator end, 
    TOutputIterator dest);

我觉得我把事情复杂化了。我喜欢用 C++ 编写相当通用的代码,但我很难锁定我的接口。但后来我陷入了我试图将所有内容模板化的困境。此时,阅读代码的人并没有意识到这TForwardIterator是在迭代std::string.

在我的特殊情况下,我想知道这种通用是否是一件好事。你什么时候开始让代码更明确?是否有一种标准方法可以从函数中获取值?

4

4 回答 4

3

是的,它不仅很好,而且是一个非常好的设计。以这种方式进行模板化是大多数标准库算法的工作方式,例如std::fillor std::copy;它们与迭代器一起使用,以便您可以填充其中已经包含元素的容器,或者您可以取一个空容器并使用std::back_inserter.

这是一个非常好的设计 IMO,并利用了模板和迭代器概念的强大功能。

你可以像这样使用它(但你已经知道了):

std::list<Url> l;
std::vector<Url> v;

x.get_urls(begin(dat1), end(dat1), std::back_inserter(l));
y.get_urls(begin(dat2), end(dat2), std::back_inserter(v));

我感觉你害怕使用模板,它们不是“正常的”C++,或者它们应该被避免并且臃肿等等。我向你保证,它们是非常正常且强大的语言功能,没有其他语言(我所知道的)具有,所以只要适合使用它们,就使用它们。而在这里,非常合适。

于 2012-09-25T15:39:48.880 回答
2

在我看来,您的界面错误。

已经有从迭代器复制到容器的算法。在我看来,您的课程提供了一个 url 流(不依赖于修改其源)。因此,您真正需要的只是一种通过迭代器(前向迭代器)公开内部数据的方法,因此您只需要提供 begin() 和 end()。

UrlExtractor             page(/* Some way of constructing page */);
std::vector<std::string> data;

std::copy(page.begin(), page.end(), std::back_inserter(data));

我只想提供以下界面:

class UrlExtractor
{
    ...... STUFF
    iterator begin(); 
    iterator end();
};
于 2012-09-25T15:54:56.417 回答
0

不知道实际用例场景很难说,但总的来说,最好避免使用模板(或任何其他不必要的复杂性),除非它真的给你买了东西。这里最明显的签名是:

std::vector<Url> UrlExtractor::get_urls( std::string const& source );

是否真的有任何可能的情况,您必须解析除 a 之外的任何内容std::string?(如果您还支持输入迭代器,可能会有。但实际上,如果您正在解析,源将是 astd::string或 an std::istream&。除非您真的想支持后者,否则只需使用std::string。)当然,客户端代码可以对返回的向量执行任何操作,包括将其附加到另一种类型的集合中。

如果返回 a 的成本std::vector确实成为问题,那么您可以将 astd::vector<Url>&作为参数。我看不到任何合理的情况,任何额外的灵活性都会给你带来很多好处,而且类似的功能get_urls可能相当复杂,而不是你想要放在标题中的那种东西。

于 2012-09-25T15:51:50.430 回答
0

是的,你太笼统了。模板的意义在于您可以生成行为不同的函数的多个副本。您可能不希望这样,因为您应该选择一种表示 URL 的方式并在整个程序中使用它。

你怎么做:

typedef std::string url;

这使您可以更改将来用于 url 的类。

也许在其中std::vector实现了一些接口,push_back()并且您的方法可以引用该接口(back_inserter?)。

于 2012-09-25T15:28:07.993 回答