C++ 是否基于范围';对于';循环反对许多简单的算法?
算法解决方案:C++ 是否基于范围';对于';循环反对许多简单的算法?,c++,algorithm,stl,c++11,foreach,C++,Algorithm,Stl,C++11,Foreach,算法解决方案: std::generate(numbers.begin(), numbers.end(), rand); for (int& x : numbers) x = rand(); 基于范围的for循环解决方案: std::generate(numbers.begin(), numbers.end(), rand); for (int& x : numbers) x = rand(); 为什么我要在C++11中使用更详细的基于范围的for循环std::gener
std::generate(numbers.begin(), numbers.end(), rand);
for (int& x : numbers) x = rand();
基于范围的for循环解决方案:
std::generate(numbers.begin(), numbers.end(), rand);
for (int& x : numbers) x = rand();
为什么我要在C++11中使用更详细的基于范围的for循环
std::generate
?for循环是否基于范围没有任何区别,它只简化了括号内的代码。算法更清晰,因为它们显示了意图。在我看来,手动循环虽然可以减少冗长,但缺乏易懂的:
for (int& x : numbers) x = rand();
我不会使用这个循环来初始化由数字定义的范围,因为在我看来,它似乎是在一个数字范围内迭代,但实际上它不是(本质上),也就是说,它不是从范围中读取,而是向范围中写入
当您使用std::generate
时,其意图更为明确
一,。在此上下文中初始化意味着为容器的元素赋予有意义的值。第一个版本
std::generate(numbers.begin(), numbers.end(), rand);
告诉我们您想要生成一系列值
在第二个版本中,读者必须自己弄清楚这一点
节省打字时间通常是次优的,因为它通常会浪费在阅读时间上。大多数代码被读取的次数比输入的次数多得多 在我看来,有效的STL第43项:“优先选择手写循环的算法调用。”仍然是一个很好的建议。 我通常编写包装函数来摆脱
begin()
/end()
地狱。如果您这样做,您的示例将如下所示:
my_util::generate(numbers, rand);
我相信它在传达意图和可读性方面都优于基于范围的for循环
话虽如此,我必须承认,在C++98中,一些STL算法调用产生了无法表达的代码,下面的“与手写循环相比,更喜欢算法调用”似乎不是一个好主意。幸运的是,兰博达斯已经改变了这一点 考虑下面的例子 任务:查找v中的第一个元素,即
>x
和
没有lambdas:
auto i = find_if( v.begin(), v.end(),
bind( logical_and<bool>(),
bind(greater<int>(), _1, x),
bind(less<int>(), _1, y) ) );
auto i=find_if(v.begin(),v.end(),
绑定(逻辑_和(),
绑定(更大的(),_1,x),
绑定(less(),_1,y));
和lambda
auto i=find_if( v.begin(), v.end(), [=](int i) { return i > x && i < y; } );
auto i=find_if(v.begin(),v.end(),[=](int i){return i>x&&i
我的答案是可能和否。如果我们谈论的是C++11,那么可能(更像是否)。例如,std::For_each
即使与lambda一起使用,也非常烦人:
std::for_each(c.begin(), c.end(), [&](ExactTypeOfContainedValue& x)
{
// do stuff with x
});
但使用基于范围的for要好得多:
for (auto& x : c)
{
// do stuff with x
}
另一方面,如果我们谈论的是C++1y,那么我会说,不,这些算法不会被基于范围的for淘汰。在C++标准委员会中有一个研究小组正在研究C++中添加范围的建议,并且在多态LAMBDAS上也有工作。范围将不再需要使用一对迭代器,多态lambda将允许您不指定lambda的确切参数类型。这意味着std::for_每个都可以这样使用(不要把这当作硬事实,这就是今天的梦想):
就我个人而言,我最初读到:
std::generate(numbers.begin(), numbers.end(), rand);
for (int& x : numbers) x = rand();
是“我们分配给某个范围内的所有对象。该范围是数字
。分配的值是随机的”
我对以下内容的初步解读:
std::generate(numbers.begin(), numbers.end(), rand);
for (int& x : numbers) x = rand();
是“我们正在对某个范围内的所有事物进行处理。该范围是数字
。我们所做的是分配一个随机值。”
这些非常相似,但不完全相同。我想引起第一次阅读的一个可能的原因是,我认为关于这段代码最重要的事实是它分配给了范围。这就是你的“我为什么要……”。我使用<代码>生成< /C> >因为在C++ <代码> STD::生成< /COD>意味着“范围分配”。顺便说一句,正如std::copy所做的那样,两者之间的区别在于您从中分配的内容
不过,也有一些令人困惑的因素。与基于迭代器的算法相比,基于范围的for循环有一种更直接的方式来表示范围是数字。这就是人们研究基于范围的算法库的原因:boost::range::generate(number,rand)
看起来比std::generate版本更好
与此相反,基于for循环的范围中的int&
是一个折痕。如果范围的值类型不是int
,那么我们在这里做一些非常微妙的事情,这取决于它是否可以转换为int&
,而生成的代码只取决于rand
返回的值是否可以分配给元素。即使值类型是int
,我仍然可能会停下来考虑它是否是。因此,auto
,它推迟了对类型的思考,直到我看到分配了什么——使用auto&x
我说“引用范围元素,不管它可能有什么类型”。回到C++03,算法(因为它们是函数模板)是隐藏精确类型的方法,现在它们是一种方法
我认为,最简单的算法与等效循环相比,只能获得边际收益,这种情况一直存在。基于范围的for循环改进了循环(主要是通过删除大部分样板文件,尽管其中还有一些内容)。因此,利润率越来越高,在某些特定情况下,你可能会改变主意。但是仍然有一个风格上的差异。对于以迭代器为输入的算法来说,使用基于范围的循环,有些事情是无法(简单地)完成的。
例如,使用std::generate
:
使用一个分布中的变量将容器填充到limit
(排除在外,limit
是numbers
上的有效迭代器),其余容器填充另一个分布中的变量
std::generate(numbers.begin(), limit, rand1);
std::generate(limit, numbers.end(), rand2);
基于迭代器的算法可以更好地控制操作范围。对于std::generate
的特殊情况,我同意