2011-05-03 88 views
4

假設您想用隨機數填充向量。然後有一個下列顯而易見的解決方案:通過STL或Boost引入僞參數

vector<int> result; 
result.resize(n); 
for (int i = 0; i < n; ++i) { 
    result[i] = generateRandomNumber(); 
} 

OK,它顯然作品,但我想了解什麼是最簡單的STL /升壓方式擺脫的for循環。使用std :: transform很誘人,但它只需要一個帶有一個參數的函數。有沒有什麼好的STL方法在函數中引入虛擬參數?

回答

5

C++標準庫有std::generate()std::generate_n();

例如:

#include <iostream> 
#include <cstdlib> 
#include <algorithm> 
#include <vector> 
#include <iterator> 
int generateRandomNumber() 
{ 
    return std::rand(); 
} 
int main() 
{ 
    int n = 10; 
    std::vector<int> result; 
    generate_n(back_inserter(result), n, generateRandomNumber); 
    copy(result.begin(), result.end(), std::ostream_iterator<int>(std::cout, " ")); 
    std::cout << '\n'; 
} 

測試:https://ideone.com/5xD6P

至於第二個問題,如果我理解正確,是如何創造一個仿函數接受一個int參數,忽略它,並呼籲你的int f()

C++ 98方法是實際寫全算符:

struct IgnoreArgument 
{ 
    typedef int(*fp_t)(); 
    fp_t fp; 
    IgnoreArgument(fp_t f) : fp(f) {} 
    int operator()(int) const { return fp(); } 
}; 
... 
transform(v.begin(), v.end(), v.begin(), IgnoreArgument(f)); 

測試:https://ideone.com/DTsyl

C++ 11的方法是使用一個lambda表達式

transform(v.begin(), v.end(), v.begin(), [](int){return f();}); 

測試:https://ideone.com/nAPXI

而C++ 98/boost的方式是使用boost::bind

transform(v.begin(), v.end(), v.begin(), boost::bind(f)); 

測試:https://ideone.com/cvd88

+0

非常感謝。但有關虛擬變量的問題仍然存在。 – 2011-05-03 18:28:15

+0

@Ilya Razenshteyn你可以舉一個如何使用這種變量的例子嗎? – Cubbi 2011-05-03 18:31:18

+0

假設我有一個函數int f(),現在我想要產生一個函數int g(int){return f(); }使用標準的東西。 – 2011-05-03 18:39:12

1

使用generate_n與你有多少元素需要,具有back_insert_iterator到您想要的地方存儲的向量一起,和一個指針生成號碼功能。

#include <vector> 
#include <algorithm> 


int generateRandomNumber() 
{ 
    static int i = 0; 
    return 42 + (i++); 
} 

int main() 
{ 
    std::vector<int> vi; 
    std::generate_n(back_inserter(vi), 10, &generateRandomNumber);  
} 

注意,通過使用back_insert_iterator像我一樣在這裏,您不必預先尺寸的載體,它是缺憾的最好的。

+0

由於性能問題,我需要預先設置它的大小。 – 2011-05-03 18:38:20

+0

@Ilya:然後用'.begin()' – 2011-05-03 18:39:25

+0

替換我的示例中的'back_inserter'謝謝,但是,關於虛擬變量的問題仍然是開放的。找到它真是太棒了。 – 2011-05-03 18:41:03

1

這裏的問題是,transform只是不是手頭任務的正確選擇。 transform的意圖是採取一些輸入,以某種規定的方式對每個輸入進行變換,併爲每個輸入產生一個輸出。

在這種情況下,你不要任何輸入。 transform如果向量中的值基於某種現有向量中的值(以某種方式或其他方式),那麼這將是有意義的。

generate_n真的是這個問題的正確解決方案 - 它打算調用N次函數/函子,生成N個結果,並將它們分配給您提供的輸出迭代器(及其後繼器)。由於它旨在生成值(而不是轉換現有值),因此函數/函子不會接受輸入,並且不必提供「假」輸入。

就「虛擬」的論點而言,想要/需要它可能是一個非常好的跡象(在這種情況下)你使用了錯誤的算法,而不應該這樣做。

但是,您確實有時會遇到相反的情況:您想使用不提供算法提供參數,但您希望能夠提供參數。例如,假設您希望能夠將陣列中的數字設置爲隨機數,並且用戶指定了一些較低和/或上限。在這種情況下,您希望能夠指定將傳遞給您的隨機數函數的邊界,但generategenerate_n都沒有任何規定來執行此操作。

在這種情況下,您有兩種可能性。一個是bind(原來是boost::bind,但現在包含在C++ 11中)。我通常喜歡使用函子,並將參數傳遞給ctor:

class gen_random { 
    int lower; 
    int upper; 
public: 
    gen_random(int lower = 0, int upper = RAND_MAX) : lower(lower), upper(upper) {} 

    int operator() { return rand_range(lower, upper); 
}; 

int main() { 
    std::vector<int> rand_ints; 

    std::generate_n(std::back_inserter(rand_ints), 10, gen_random(1, 6)); 
    return 0; 
}