2012-04-03 24 views
36

C++11中,所有元素都有兩個循環(基於for和for_each的範圍)。有沒有什麼理由比另一方更喜歡它,或者是否有一種更適合的情況?首選標準用途:基於範圍或for std :: for_each

for (auto& elem: container) { 
    // do something with elem 
} 

std::for_each(container.begin(), container.end(), 
       [](Elem& elem) { 
       // do something with elem 
       }); 

我的想法是,首先是簡單的,類似於範圍在其他語言中基於循環而第二也適用於那些不完整的集裝箱序列和第二個是更類似於其他std -algorithms。

+0

我很好奇實際正確使用基於範圍的方法,所以請看我的問題http://stackoverflow.com/questions/9994789/proper-style-for-declaration-in -range-based-for – Potatoswatter 2012-04-03 13:57:18

+0

我添加了一個簡單的'for_each'示例。我以爲我看到一個消息要求一個,但我不太確定... – juanchopanza 2012-04-03 14:09:05

+0

@juanchopanza:我問了一個基於拉姆達的,但我刪除它,因爲在我發佈評論時,我閱讀Potatoswatter的評論,即查詢lambda是不可能的。不過,這是一個很好的例子,說明for_each可能更適合。 – stefaanv 2012-04-03 14:13:04

回答

26
  1. 基於範圍的for明顯更易於讀寫。它專門用於這項任務。

    編輯:你可以在不濫用例外的情況下打破範圍。 (雖然對於std::find_if取代std::for_each允許這一點。)

  2. std::for_each,諷刺,是這實際上是一系列基於並允許用戶選擇,而不是整個容器特定beginend值替代。 (編輯:這可以圍繞使用簡單range類提供beginend成員,如由升壓提供被黑客攻擊。)當以其它方式使用高階函數

    另外for_each可能更優雅:它可以用來作爲bind的參數,第三個參數已經是一個仿函數。

主要是它的風格問題。儘管大多數讀者可能更喜歡看到for (auto &a : b),現在大多數實現都支持它。

+0

+1的確,你可以在'for_each'中選擇範圍的事實非常強大。 – juanchopanza 2012-04-03 13:53:13

+5

@juanchopanza:當然,如果你使用'Range'容器(比如'Boost.Range'),那麼這個優點是沒有意義的。 – 2012-04-03 14:21:11

+5

您可能想要添加該範圍 - 允許中斷並繼續。 – Klaim 2012-04-03 15:22:12

10

std::for_each返回循環內部使用的函數,因此它提供了一個乾淨的機制來收集有關序列中元素的一些信息。基於循環的範圍只是一個循環,因此任何在循環外部使用的狀態都必須在該範圍之外聲明。在你的例子中,如果循環的目的是改變序列中的每個元素,那麼根本沒有太大的區別。但是如果你沒有使用for_each的返回值,那麼你可能會用簡單的循環更好。順便說一下,基於範圍的循環也適用於C風格的數組和std :: strings。

這是一個使用返回值for_each的示例,雖然它不是一個非常有想象力或有用的。這只是爲了說明這個想法。

#include <iostream> 
#include <array> 
#include <algorithm> 

struct Foo { 
    void operator()(int i) { if (i > 4) sum += i;} 
    int sum{0}; 
}; 

int main() { 

    std::array<int, 10> a{1,2,3,4,5,6,7,8,9,10}; 
    Foo foo = std::for_each(a.begin(), a.end(), Foo()); 
    std::cout << "Sum " << foo.sum << "\n"; 
} 
+1

+1,但請注意,無論如何都無法查詢lambda仿函數;獲取輔助狀態將通過一個捕獲變量來完成,這個捕獲變量在任何一個構造中都是一樣的。 – Potatoswatter 2012-04-03 13:49:59

+0

@Potatoswatter好點。或者通過從lambda創建一個函數對象。 – juanchopanza 2012-04-03 13:52:15

+2

@juanchopanza:確實,幸運的是,這裏的情況還是從C++ 03中得到了改進。在C++ 03中,如果您將獲得完整結果(因爲副本),則未指定,而在C++ 11中僅使用移動操作。 – 2012-04-03 14:24:12

相關問題