STL算法:为什么没有容器的附加接口(除了迭代器对)?

lee*_*mes 17 c++ stl overloading stl-algorithm c++11

我想知道为什么STL不会重载它们的算法函数,这样我就可以通过简单地提供一个容器而不是采用更冗长的方式来传递begin + end迭代器来调用它们.我当然理解为什么我们也想使用迭代器对来处理容器/数组的子序列,但是,几乎所有对这些方法的调用都使用整个容器:

std::for_each(myVector.begin(), myVector.end(), doSomething);
Run Code Online (Sandbox Code Playgroud)

我发现它只是更方便,可读和可维护

std::for_each(myVector, doSomething);
Run Code Online (Sandbox Code Playgroud)

有没有理由STL不提供这些重载?[编辑:我的意思并不是要取代这个接口的限制之一,但要提供了基于容器的iterface!]难道他们介绍歧义?我在考虑这样的事情:

template<typename _Container, typename _Funct>
inline _Funct for_each(_Container c, _Funct f) {
    return for_each(begin(c), end(c), f);
}
Run Code Online (Sandbox Code Playgroud)

我错过了什么吗?

Bo *_*son 18

它们确实为许多算法引入了歧义.很多<algorithm>看起来像

template<class iterator>
void do_something(iterator, iterator);

template<class iterator, class funct>
void do_something(iterator, iterator, funct);
Run Code Online (Sandbox Code Playgroud)

如果添加其他重载

template<class container, class funct>
void do_something(container, funct);
Run Code Online (Sandbox Code Playgroud)

编译器在找出具体方法时会遇到一些麻烦do_something(x, y).如果xy是相同type,它将匹配iterator = typecontainer = type, funct = type.*)

C++ 11尝试用"概念"来解决这个问题,这些概念可以识别容器和迭代器之间的区别.然而,这些"概念"变得太复杂而无法使其成为标准,因此这些超载也没有.

*) 编译器在这里不同意,Comeau编译器声称它不明确,g ++ 4.5和MSVC 10调用第一个函数.


在评论中进行了长时间的讨论之后,这里有一个例子,它没有按预期工作 - 使用容器适配器也可以兼作谓词.

#include <iostream>
#include <vector>

template<class iterator>
void test(iterator, iterator)
{
   std::cout << "test iterator\n";
}

template<class iterator, class predicate>
void test(iterator, iterator, predicate)
{
   std::cout << "test iterator, predicate\n";
}

template<class container, class predicate>
void test(const container& cont, predicate compare)
{
   std::cout << "test container, predicate\n";

   test(cont.begin(), cont.end(), compare);
}

template<class container>
class adapter
{
public:
   typedef typename container::iterator   iterator;

   adapter(container* cont) : cont(cont)
   { }

   iterator begin() const
   { return cont->begin(); }

   iterator end() const
   { return cont->end(); }

   bool operator()(const iterator& one, const iterator& two)
   { return *one < *two; }

private:
   container* cont;
};

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

   adapter<std::vector<int>>   a(&v);

   test(a, a);

}
Run Code Online (Sandbox Code Playgroud)

输出:

测试迭代器

http://ideone.com/wps2tZ


Pup*_*ppy 10

不幸的是,这是一个更普遍的问题; 也就是说,迭代器旨在击败那些糟糕的C API和Java风格的"将算法作为每个单独容器的方法"解决方案.它们是第一代通用解决方案,毫无疑问,经过反思,它们不像我们花了二十年时间考虑它后可获得的其他可能的通用解决方案那么好.

添加这些容器重载只会在问题空间的一小部分上进行频带辅助; 甚至可能会在未来使事情变得更糟.解决方案是范围,C++希望尽快引入.

  • @leemes:STL*是*第一代通用解决方案.C++ 11仍然向后兼容(主要)与C++ 03,并且不能抛弃旧形式而不是新形式:它们必须共存.不幸的是,它们之间存在着模糊不清的现象(看看Bo Persson对解释的回答).然而,没有什么是确定的,如果我们得到概念,我们可能最终得到STL*中的范围*.现在,Boost.Range可以缓解你的困境. (2认同)