C++ 为什么序列运算算法谓词是通过副本传递的?
我想知道为什么函子是通过copy传递给函数的:C++ 为什么序列运算算法谓词是通过副本传递的?,c++,c++11,stl-algorithm,C++,C++11,Stl Algorithm,我想知道为什么函子是通过copy传递给函数的: template <typename T> struct summatory { summatory() : result(T()) {} void operator()(const T& value) { result += value; std::cout << value << "; ";}; T result; }; std::array<int, 10
template <typename T> struct summatory
{
summatory() : result(T()) {}
void operator()(const T& value)
{ result += value; std::cout << value << "; ";};
T result;
};
std::array<int, 10> a {{ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 }};
summatory<int> sum;
std::cout << "\nThe summation of: ";
std::for_each(a.begin(), a.end(), sum);
std::cout << "is: " << sum.result;
之所以发生这种情况,是因为函子是通过复制而不是引用传递给的:
template< class InputIt, class UnaryFunction >
UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );
template
每个_的一元函数(先输入,后输入,一元函数f);
因此外部函子保持不变,而内部函子(它是外部函子的副本)更新并在执行算法()后返回,因此在执行所有操作后,结果再次被复制(或移动)
这样做肯定有很好的理由,但我真的没有意识到这种设计的基本原理,所以我的问题是:
- 为什么序列运算算法的谓词是通过复制而不是引用传递的
- 在参考传递方法之前,复制传递方法有哪些优势
- 这主要是出于历史原因。在98年,当所有的algo程序都进入标准参考时,出现了各种各样的问题。这最终通过C++03及更高版本的核心和库DRs得到解决。另外,合理的ref包装器和实际工作绑定只在TR1中到达
那些尝试在早期C++98中使用algos并使用ref参数或returns函数的人可以回忆起各种各样的麻烦。自编算法也容易遇到可怕的“引用到引用”问题
通过值传递至少工作得很好,几乎不会产生很多问题——boost很早就有了ref和cref来帮助您解决需要调整的地方。也许这是一个解决方法。捕获函子作为引用,并在lambda中调用它
std::for_each(a.begin(), a.end(), [&sum] (T& value)
{
sum(value);
});
std::cout << "is: " << sum.result;
std::for_each(a.begin()、a.end()、[&sum](T&value)
{
总和(价值);
});
这纯粹是猜测,但是
…让我们暂时假设它通过引用const。这意味着您的所有成员都必须是可变的,并且运算符必须是常量。那就是感觉不“对”
。。。让我们暂时假设它通过引用non-const。它会调用一个非常量操作符,成员只需对其进行精细处理即可。但是如果你想传递一个特别的对象呢?就像绑定操作的结果一样(甚至C++98都有——丑陋而简单的——绑定工具)?或者类型本身只是做你需要的所有事情,之后你不需要对象,只想对每个对象调用(b,e,my_functor())代码>?这是行不通的,因为临时变量不能绑定到非常量引用
因此,也许不是最好的,但最不坏的选择是按值取,在过程中根据需要复制它(希望不要太频繁),然后在完成后,为每个人返回它。这在求和对象的复杂性相当低的情况下可以很好地工作,不需要添加可变的东西,比如对常量的引用方法,并且也适用于临时对象
但是YMMV,以及委员会成员可能会这样做,我猜这最终是对他们认为最有可能适合大多数用例的内容的投票。这很好!,但我并不是在寻找解决方法(但我还是会使用它!):P我只是想知道为什么这个算法的函数签名不是一个referenceHmm。。此链接尝试完成与您相同的操作:。也许可以试试。也许(for(inti:a){sum(i);}
更简单?你能用一些参考来支持吗?在过去的二十年中,我没有听说过任何关于引用的“各种各样的问题”,尤其是C++03中修复的问题,这些问题不能证明在标准库中不使用它是合理的。当然,请在WG21论文中查找缺陷报告。LDR109固定的bind1st和bind2nd只是一个很小的例子我对一个历史性的答案感到失望:(我本想从我的知识中找出一些微妙的性能原因。但这个答案几乎回答了我的两个问题。@BalogPal:我不会真的称之为“引用的所有问题”,特别是因为它在库中有一些错误,并且不是一个根本性的问题,引用可能会使它们不需要在库中使用。@PaperBirdMaster如果您真的想知道性能原因,Chandler的C++Now注释记号可能会提供一些,尽管这肯定不是决策过程的一部分。请注意for_如何返回“ready”object为什么不使用基于范围的循环?for(inti:a){sum(i)}
如果需要,我会使用它,但问题不是如何进行总结,而是关于算法库。例如,如果stl算法将采用非常量引用,那么对于每个(…,只需从\u cout\u arg\u到\u std\u out())
不会编译,不会回答问题,只需使用std::acculate
进行求和,如果需要有状态谓词,则可以始终将状态存储在谓词外部。
std::for_each(a.begin(), a.end(), [&sum] (T& value)
{
sum(value);
});
std::cout << "is: " << sum.result;