2016-02-27 65 views
1

這是我從http://www.catonmat.net/blog/on-functors/複製的函子代碼。函子與在C++中的std ::的for_each

#include <algorithm> 
#include <iostream> 
#include <list> 

class EvenOddFunctor { 
    int even_; 
    int odd_; 
public: 
    EvenOddFunctor() : even_(0), odd_(0) {} 
    void operator()(int x) { 
     if (x%2 == 0) even_ += x; 
     else odd_ += x; 
    } 
    int even_sum() const { return even_; } 
    int odd_sum() const { return odd_; } 
}; 

int main() { 
    EvenOddFunctor evenodd; 

    int my_list[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 
    // ??? why assign 
    evenodd = std::for_each(my_list, 
        my_list+sizeof(my_list)/sizeof(my_list[0]), 
        evenodd); // ??? 

    std::cout << "Sum of evens: " << evenodd.even_sum() << "\n"; 
    std::cout << "Sum of odds: " << evenodd.odd_sum() << std::endl; 

    // output: 
    // Sum of evens: 30 
    // Sum of odds: 25 
} 

爲什麼我們需要在evenodd = std::for_each(my_list,手術後分配值回evanodd對象?我認爲,因爲evenodd對象是從std :: for_each更新的,所以我不需要賦值操作,但是如果沒有此賦值,結果將顯示0.

回答

2

std::for_each按值接受functor,這意味着它會修改本地副本。該分配將獲取該本地副本,以便您可以實際看到修改後的版本。

這很重要,因爲你的仿函數有你感興趣的可變狀態,特別是evenodd.even_sumevenodd.odd_sum

1

讓我們做一些實驗。

首先,儘量不要給它分配,看看會發生什麼。在你嘗試之後,如果你知道了,就沒有必要再讀,所以你可以停下來。

如果你不能弄清楚,讓我們做第二個實驗中,並改變你的main()的相關部分如下:

const EvenOddFunctor evenodd_orig; 

int my_list[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 
// ??? why assign 
auto evenodd = std::for_each(my_list, 
       my_list+sizeof(my_list)/sizeof(my_list[0]), 
       evenodd_orig); // ??? 

這裏的關鍵部分是,你傳遞一個不變反對std::for_each。這將編譯,但如果std::for_each工作的方式你認爲它的工作,這不應該編譯。

畢竟,operator()恆定的方法,所以用std::for_each得到一個const引用,它不應該是能夠調用您的可變operator()方法。

那是因爲什麼本質上發生的是std::for_each讓您傳遞給它的仿函數的內部副本。它的值函數參數,而不是參考,你的仿函數最終修改它的內部狀態。

這就是爲什麼std::for_each在完成時返回仿函數對象,這就是爲什麼您需要保存它,因爲傳遞到std::for_each的原始對象沒有被修改!

相關問題