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

2022-01-07 00:00:00 overloading c++ c++11 stl stl-algorithm

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

I'm wondering why the STL doesn't overload their algorithm functions such that I can call them by simply providing a container and not taking the more verbose way to pass begin + end iterators. I of course understand why we also want to use an iterator pair for processing subsequences of a container / array, however, almost all calls to these methods are using a whole container:

std::for_each(myVector.begin(), myVector.end(), doSomething);

我觉得只写更方便、可读和可维护

I'd find it more convenient, readable and maintainable to just write

std::for_each(myVector, doSomething);

STL 不提供这些重载是否有原因?它们是否引入了歧义?我正在考虑这样的事情:

Is there a reason STL doesn't provide these overloads? Do they introduce ambiguity? I'm thinking about something like this:

template<typename _Container, typename _Funct>
inline _Funct for_each(_Container c, _Funct f) {
    return for_each(begin(c), end(c), f);
}

我错过了什么吗?

推荐答案

他们确实为许多算法引入了歧义.很多看起来像

They do introduce ambiguity for many algorithms. A lot of <algorithm> looks like

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

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

如果你添加额外的重载

template<class container, class funct>
void do_something(container, funct);

编译器在弄清楚 do_something(x, y) 的含义时会遇到一些麻烦.如果 xy 是相同的 type,它将匹配 iterator = type 和 <代码>容器 = 类型,功能 = 类型.*)

the compiler will have some trouble figuring out what do_something(x, y) means. If x and y are of the same type, it will match both iterator = type and container = type, funct = type.*)

C++11 试图用 "concepts" 解决这个问题,它可以识别容器和迭代器.然而,这些概念"被证明过于复杂,无法纳入标准,因此这些重载也没有.

C++11 tried to solve this with "concepts" that could recognize the difference between a container and an iterator. However, these "concepts" turned out to be too complicated to make it into the standard, so neither did these overloads.

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

在评论中进行了非常长时间的讨论后,这里有一个无法按预期工作的示例 - 使用还可以兼作谓词的容器适配器.

After an extremely long discussion in the comments, here is one example where it doesn't work as expected - using a container adapter that can also double as a predicate.

#include <iostream>
#include <vector>

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

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

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

   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);

}

输出:

测试迭代器

http://ideone.com/wps2tZ

相关文章