These questions让我对每个宏的Boost和Qt 的目的感到好奇。
我已经使用过Qt,并发现宏一直能够满足我的需求,但从未对其性能进行过广泛的测试。我之前没有使用过Boost的产品。
我想知道的是,在std::for_each
使用Qt和Boost提供的替代方案的时候会是什么时候?
注意:措辞已从the original更改为更加客观。
答案 0 :(得分:5)
std::for_each
的目的和功能与宏BOOST_FOREACH
和Q_FOREACH
的目的和功能大不相同。
std::for_each
首先是函数调用。这是一种算法。你调用它,提供一对迭代器。在迭代器范围的每个成员上,它将使用从相关迭代器获取的值调用给定函数。
从概念上讲,std::for_each
的目的实际上是与已经存在的更具体的算法相匹配。使用count
,copy
等算法,有一个只为每个元素执行任意代码的方法。
BOOST_FOREACH
和Q_FOREACH
是等效的构造(我将统称为FOREACH
),但的行为与std::for_each
不同。
FOREACH
首先是 for循环。现在,这可能听起来不那么不同,但想一想。您无法从continue
内拨打break
和std::for_each
。使用continue
可以轻松模拟return
(尽管这也意味着您无法从发出std::for_each
调用的函数返回)。但如果你想停下来,就没有办法摆脱std::for_each
循环。同样,您不能goto
循环for_each
。在任何一种情况下你能做的最好就是抛出一个异常,那就是使用流控制的异常(即:不是一个好主意)。
使用std::for_each
时,必须提供一些可调用的功能。这可以是函数指针或函数对象。因此,您的代码在某种程度上是非本地化的。如果您在每次迭代中所做的事情是复杂的多线函数,那么这很好。但是,如果每个迭代的逻辑非常简单,那么代码可读性会稍微降低。
FOREACH
执行本地代码块。所以代码就在那里;你不必追踪一个函数来看每次迭代发生了什么。
此外,调用函数意味着必须编写该函数。如果你需要跟踪状态,你现在需要一个仿函数,这需要更多代码来编写。
使用lambda函数,C ++ 11使std::for_each
更具吸引力。这消除了代码局部性问题:源代码就在那里。由于lambdas可以捕获内容,因此它几乎可以像常规for
循环一样工作。好吧,除了没有break
功能,但这通常是可以避免的。
当然,C ++ 11还使其有效地过时(以及FOREACH
)具有基于范围的for
循环。但由于与C ++ 11存在不同的一致性,因此在某些环境中您拥有lambda而不是基于范围的for
。
您应该使用的内容取决于您。 FOREACH
很好,如果你已经使用了Boost和/或Qt,那么请随意。但我不会突然开始只为FOREACH
使用这些。就个人而言,我不会使用std::for_each
,除非您还使用lambdas或其他东西,因为代码位置问题。只需使用for
循环。
答案 1 :(得分:1)
std::for_each
是C ++标准的一部分,自1998年以来(至少)。因此,任何(不那么)现代C ++都是不合规的,因此如果它不提供for_each
则会被破坏。我每天使用的所有编译器都支持它。
您提到的两个库都存在于C ++语言之外。 for_each
是唯一一个保证符合标准的编译器。
至于利弊,我留给你决定。如果有一个选择,我会选择标准保证的东西,而不是。
答案 2 :(得分:1)
std :: for_each需要执行仿函数, lambda 或函数指针。使用它,如果在代码中的多个位置循环使用相同的方法,则可以避免大量样板。
void hello(int i){
printf("World %d \n",i);
}
std::vector<int> vals;
vals.push_back(1);
vals.push_back(2);
std::for_each(vals.begin(),vals.end(),hello);
BOOST_FOREACH和Q_FOREACH用于隐藏c ++迭代器的样板,它们替换正常的for语句并循环遍历循环体。
for(vector<int>::iterator iter = vals.begin();iter != vals.end();++iter)
{
hello(*iter);
}
Q_FOREACH(int val, vals){
hello(val);
}
用法:您认为哪种方式最具可读性,避免不必要的代码重复。
性能:这些中的每一个都是宏或模板函数,并且对编译器完全可见,差异应仅存在于调试版本中(如果有的话)。