C++ 14剛在上個月通過,C++14給C++11帶來了一些令人期待的改變,例如允許auto作為一個函式的返回型別,還有泛型lambdas,這也是我們這篇文章的主題。
C++11 引入了 Lambdas,它意味著你可以把程式碼寫的更短,匿名的函式,而不用一個函式,避免了建立一個單獨的類和單獨的函式定義,這裡有一個典型的C++11中lambda的使用例子,返回一個數字的平方,
1 2 |
int result = [](int input) { return input * input; }(10); cout << result << endl; |
如果你想在很多地方使用這個程式碼片段,你可以把它儲存到一個變數中
1 2 3 4 5 6 7 |
auto func = [](int input) { return input * input; }; // first use std::cout << func(10) << std::endl; // second use std::cout << func(23) << std::endl; |
你可以想到上面的程式碼會出什麼問題了嗎,它只是針對整數型別,如果你想把這個函式用在double或者複數型別的數字,像這樣
1 2 3 4 5 6 7 8 |
// square of an int std::cout << func(10) << std::endl; // square of a double std::cout << func(2.345) << std::endl; // square of a complex number std::cout << func(std::complex<double>(3, -2)) << std::endl; |
這裡明顯只能使用模板
1 2 3 4 |
template <typename T> T func(T z) { return z * z; } |
很顯然,我們這裡不是尋求這種解決方案,上面的這個函式不是匿名的,而是一個全域性的函式,
C++14 標準中引入了泛型lambda的概念,允許我們使用auto來定義lambda的引數型別,我們可以寫一個更短的更優雅的程式碼
1 |
auto func = [](auto input) { return input * input; }; |
下面是完整一點的程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include<iostream> #include<complex> int main() { // Store a generalized lambda, that squares a number, in a variable auto func = [](auto input) { return input * input; }; // Usage examples: // square of an int std::cout << func(10) << std::endl; // square of a double std::cout << func(2.345) << std::endl; // square of a complex number std::cout << func(std::complex<double>(3, -2)) << std::endl; return 0; } |
上面的程式碼可以使用主流的C++編譯器編譯,像GCC4.9x, 或者Clang,下面是一個在OSX上使用GCC和Clang編譯執行的結果
1 2 3 4 5 6 7 8 9 10 11 |
$ clang++ -std=c++1y -pedantic -Wall -stdlib=libc++ test_01.cpp -o test_01 $ ./test_01 100 5.49903 (5,-12) $ g++-4.9.1 -std=c++14 -pedantic -Wall test_01.cpp -o test_01 $ ./test_01 100 5.49903 (5,-12) $ |
然而,真正泛型lambda的發光點是和STL結合使用的時候,如果你想以遞減的順序對一個vector排序,使用泛型lambda,我們可以這樣寫:
1 |
std::sort(V.begin(), V.end(), [](auto i, auto j) { return (i > j); }); |
下面是完整的程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include<iostream> #include<vector> #include<numeric> #include<algorithm> int main() { std::vector<int> V(10); // Use std::iota to create a sequence of integers 0, 1, ... std::iota(V.begin(), V.end(), 1); // Print the unsorted data using std::for_each and a lambda std::cout << "Original data" << std::endl; std::for_each(V.begin(), V.end(), [](auto i) { std::cout << i << " "; }); std::cout << std::endl; // Sort the data using std::sort and a lambda std::sort(V.begin(), V.end(), [](auto i, auto j) { return (i > j); }); // Print the sorted data using std::for_each and a lambda std::cout << "Sorted data" << std::endl; std::for_each(V.begin(), V.end(), [](auto i) { std::cout << i << " "; }); std::cout << std::endl; return 0; } |
下面是執行編譯的結果
1 2 3 4 5 6 7 |
$ g++-4.9.1 -std=c++14 -pedantic -Wall test_02.cpp -o test_02 $ ./test_02 Original data 1 2 3 4 5 6 7 8 9 10 Sorted data 10 9 8 7 6 5 4 3 2 1 $ |