STL的算法:为什么集装箱没有额外的接口(除迭代器对)?(STL algorithms: Why n

2019-07-17 12:09发布

我不知道为什么STL不超载他们的算法函数,这样我可以通过简单地提供一个容器,而不是采取了更详细的方式来传递开始终点+迭代器调用它们。 我当然明白为什么我们也想用一个迭代器对用于使用的是整个容器处理子序列的容器/阵列的,然而,这些方法几乎所有来电:

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

我觉得它更方便,可读性和可维护性只写

std::for_each(myVector, doSomething);

是否有一个原因STL不提供这些超载 ? [编辑:我的意思并不是要取代这个接口的限制之一,但提供基于容器的iterface!]难道他们介绍歧义? 我想是这样的:

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

我缺少的东西吗?

Answer 1:

他们了很多算法引入歧义。 很多<algorithm>看起来像

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 = typecontainer = type, funct = type *)

C ++ 11试图与解决这个“概念” ,可以识别容器和迭代器之间的差异。 然而,这些“概念”横空出世,太复杂,使之成为标准,所以也没有这些重载。

*) 不同意的编译器在这里,所述编译器科莫声称它是不明确的,克++ 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);

}

输出:

迭代测试

http://ideone.com/wps2tZ



Answer 2:

不幸的是,这是一个更为通用的问题; 即,该迭代器被设计击败那些蹩脚ÇAPI和Java风格“把算法为每个单独容器的方法”解决方案。 他们是第一代通用的解决方案,而且也没有奇怪,细想起来,他们不是为获得后,我们花20年思考它的其他可能的解决方案的通用一样好。

添加这些集装箱重载将只是带辅助在问题空间的一小部分; 它甚至可能会使事情在未来恶化。 该解决方案是范围,其C ++正在寻求尽快介绍。



Answer 3:

据了解,我觉得一个人必须要了解的C ++算法的理念。 让我们先问这个问题:

为什么C ++算法实现为免费功能,而不是成员函数?

那么答案是非常简单的:避免实施爆炸。 假设你有M容器和N算法,如果你实现它们作为容器的成员,那么就会有M*N实现。 有这种方法的两个(相关)的问题:

  • 首先,它不使用的代码重用。 大部分的实现将重复。
  • 其次,实施爆炸,这是上面的一个直接后果。

C ++通过实施他们作为免费功能,让你只有解决了这些问题N实现。 每个容器上操作的算法的需要一对迭代的,限定的范围内 。 如果您希望采取的容器,而不是对迭代的过载,那么标准必须为每个算法提供这样的过载,又会有2*N实现这几乎打败真正目的为何C ++已经从分离算法这些功能摆在首位的容器,另一半没有做任何事情不能被另一半来完成。

所以,我不认为这是个大问题。 只是为了避免单一的说法,为什么实现N更多的功能(这也强加给它的使用有一定的约束 ,如您不能通过指针的话)? 不过,如果程序员在他们的效用希望这样的功能,他们可以在任何时候实现它们是基于标准的算法对许多其他人一样!


您的评论:

那么,2 * N的实现实际上n只有实现。 其他N的人是内联的直接调用该算法的“真正”的版本重载,所以他们是一个只有标题 - 事物。 提供集装箱重载不打败的目的,从容器中的单独算法,(你可以在我的例子中看到的),他们可以使用模板来处理所有类型的容器。

根据这一逻辑,一个可以很好地主张M*N算法。 因此,要使他们的成员函数太(和内部调用free函数)? 我相信很多人OOP宁愿

auto result = container.accumulate(val);

过度

auto result = std::accumulate(container.begin(), container.end(), val);


Answer 4:

下面是香草萨特的博客相关的答案: 为什么没有基于容器的算法 。 它显示了反例就像博佩尔松的确在他的回答以上。



Answer 5:

有一个范围运营商库与有意解决这个问题。 冗长用砍几刀。

你的例子是这个样子:

auto newVector = myVector * doSomething;

是的, doSomething -是没有括号。

熟悉成语从壳(以标准算法):

auto t = vector<int>{3,2,1,4} | sort | unique; 


Answer 6:

应该指出的是,它很容易定义你自己的琐碎包装增加集装箱的版本。

例如:

template<typename Container, typename Func>
Func for_each(Container& c, Func f) {
    return std::for_each(c.begin(), c.end(), f);
}

现在你可以让你想简单的调用。 有没有歧义,因为你的包装不在std命名空间。 您可以定义常量采取集装箱和重载。 如果你想调用的C ++版本 - 11常量迭代方法(如CBEGIN()),我认为你需要以不同的方式命名包装。 我用for_each_const。



Answer 7:

显然,作为其他用户提到,这是一个棘手的问题,所以遗憾的是它是一个漫长的时间,还是有标准库无解。 有,但是,范围已经可用的库,例如升压::范围和一个在提供的不只是你在你的问题描述接口的简易土坯源库,但有些发烧友的功能,以及。

你的榜样工程完全与加速(我们using namespace boost::range::adaptors下图):

boost::for_each(myVector, doSomething);

我们也可以切片myVector快速,轻松地:

boost::for_each(myVector | sliced(10, 20), doSomething)

我们甚至可以压缩myVector另一个,过滤器由一个谓词,并在一个单一的,简单的语句样的元素对所有其他元素(这需要你在doSomethingElse解压所产生的元组boost::combined ):

boost::for_each( boost::combined(myVector, myOtherVector) | strided(2), doSomethingElse)



文章来源: STL algorithms: Why no additional interface for containers (additional to iterator pairs)?