【问题标题】:Why can't for_each modify its functor argument?为什么 for_each 不能修改它的函子参数?
【发布时间】:2010-01-20 14:34:21
【问题描述】:

http://www.cplusplus.com/reference/algorithm/for_each/
一元函数取一个元素 范围作为参数。这既可以 是指向函数或 类重载的对象 操作员()。它的返回值,如果有的话, 被忽略。

根据这篇文章,我预计 for_each 实际上会修改作为其第三个参数给出的对象,但似乎 for_each 操作的是一个临时对象,甚至不修改给它的对象。

那么,为什么要这样实现呢?它似乎用处不大。还是我误解了什么,下面的代码包含错误?

#include <iostream>
#include <vector>
#include <algorithm>

template <class T> struct Multiplicator{
    T mresult;
  public:
    const T& result() const{return mresult;}
    Multiplicator(T init_result = 1){
      mresult = init_result;
    }
    void operator()(T element){
      mresult *= element;
      std::cout << element << " "; // debug print
    }
};

int main()
{
    std::vector<double> vec;
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);
    Multiplicator<double> multiply;
    std::for_each(vec.begin(),vec.end(),multiply);
    std::cout << "\nResult: " << multiply.result() << std::endl;
    return 0;
}

预期输出:

1 2 3 Result: 6

但得到以下输出:

1 2 3 Result: 1

【问题讨论】:

  • 改变你的问题标题怎么样?可能会让其他人更容易找到。

标签: c++ stl foreach


【解决方案1】:

函数对象是按值取值的。 for_each返回函数对象,所以如果你改成:

multiply = std::for_each(vec.begin(),vec.end(),multiply);

你得到了预期的输出。

【讨论】:

  • 通常用于仿函数,并且因为它们应该是轻量级和可复制的,所以我作弊并使用引用传递给构造函数的变量的属性。因此,任何副本都是严格等价的,并且指的是同一个项目。当然,它使初始化有点尴尬(声明变量,将其传递给函子,从变量中读取),但它工作正常并且不需要任何特定的实现适当性(例如不丢弃刚刚修改的函子)。
  • 让我给你第一个金STL徽章
  • @Johannes:谢谢,但我必须先回答另外 36 个标记为 [stl] 的问题 :-)(现在要求至少有 1,000 个赞成票和至少 200 个答案;我记得他们什么时候改变的一年前,我失去了我的金 [c] 徽章几个月。)
【解决方案2】:

虽然 James 是正确的,但使用 std::accumulatestd::multiplies 会更正确,可能:

#include <iostream>
#include <functional>
#include <numeric>
#include <vector>

int main(void)
{
    std::vector<double> vec;
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);

    double result = std::accumulate(vec.begin(), vec.end(),
                                    1.0, std::multiplies<double>());

    std::cout << "\nResult: " << result << std::endl;

}

使用您的for_each 版本,您实际上不需要再次复制函子,而是:

double result = std::for_each(vec.begin(), vec.end(), multiply).result();

或者 C++0x,为了好玩:

double result = 1;
std::for_each(vec.begin(), vec.end(), [&](double pX){ result *= pX; });

【讨论】:

  • 这是什么,“为工作日推荐合适的工具?” :-) +1
  • @James: 8​​​​​​​)不幸的是,随着时间的推移,我的答案质量呈指数级下降。 :p
【解决方案3】:

For_each 的语义不适合您尝试做的事情。积累完全符合您的要求,请改用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-31
    • 2010-10-09
    • 2020-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多