c++ primer 筆記,第十章(泛型算法)

  1. accumulate第三個三處所傳的儲值的類型必須定義了 “+”運算符,例如:將空串當作一個字面值傳給第三個參數是不可以的

    //會導致編譯錯誤,const char*上並沒有定義"+"運算符
    string sum = accumulate(v.cbegin(), v.cend(), "");
    //string上定義了"+"運算符
    string sum = accumulate(v.cbegin(), v.cend(), string("")); 
  2. 只接受一個單一迭代器來表示第二個序列的算法,都假設第二個序列至少與第一個序列一樣長;
  3. back_inserter是一種向容器中添加元素的迭代器,當我們通過此迭代器賦值時,賦值運算符會調用push_back;

    vector<int> vec;   //創建一個空vector
    fill_n(back_inserter(vec), 10, 0);  //添加10個元素到vec
  4. 關於lambda表達式:
    (1)表示一個可調用的代碼單元,可以將其理解爲一個未命名(編譯器會給它命名)的內聯函數;其實是一個函數對象,[ ] 稱爲lambda introducer,取用外部的變量要放在[ ]中;

    auto f = [] {
        std::cout << "hello lambda" << std::endl;
    };
    f();       // prints "hello lambda"

    (2)可能定義在函數內部,必須使用尾置返回,不能有默認參數,可以直接使用定義在當前函數之外的名字,例如cout;
    (3)可以忽略參數列表和返回類型,但必須永遠包含捕獲列表和函數體;
    (4)可以傳值或者傳引用,要修改傳進來的數據必須在()後聲明 mutable;被捕獲的值是在創建時拷貝,而不是調用時拷貝;
    (5)可以在lamada函數體內部像其他函數一樣定義static變量等等;
    (6)可以使用隱式捕獲,但不推薦;
    (7)當定義一個lambda時,編譯器生成一個與lambda對應的新的(未命名的類類型),使用auto定義一個用lambda初始化的變量時,定義了一個從lambda生成的類型的對象;
    (8)lambda主要應用於原來我們傳給標準庫的一些函數的自定義參數時,比如sort函數,現在我們可以改用lambda表達式來自定義我們的比較函數,表達更方便;原來我們傳遞給標準庫有些函數(比如find_if)的任何函數都只能接受一個參數,現在我們可以使用lambda來解決這個問題

    int id = 0;
    //由於是傳值,內部改變不會影響外部,並且對應於(4),被捕獲的值是在創建時拷貝,不是調用時拷貝
    auto f = [id]()mutable {  //由於使用mutable進行說明,所以可以在內部改變id的值,否則不能改變
    std::cout << "id:" << id << std::endl;
    ++id;
    };
    id = 42;
    f(); f(); f(); //id:0 id:1 id:2
    /*該lambda表達式可以類似爲下面的class,但還有一些差別*/
    class Functor {
    private:
        int id;
    public:
        void operator() {
        std::cout << "id:" << id << std:endl;
        ++id;
        }
    };
    Functor f;
  5. 佔位符,形式爲_n,n表示第幾個參數;定義在名爲placeholders的命名空間中,這個命名空間本身又定義在std中; using namespace std::placeholders; placeholders空間定義在functional頭文件中
  6. 可以將bind函數看做一個通用的函數適配器,可以使用佔位符對原函數重新包裝
    (1)重排參數順序

    //g是是一個有兩個參數的可調用對象
    auto g = bind(f, a, b, _2, c, _1);
    //生成一個新的可調用對象g,g的第一各參數被傳遞給f作爲最後一個參數,g的第二個參數被傳遞給f當做第三個參數
    // 調用g(X, Y); 相當於調用 f(a, b, Y, c, X);

    (2)綁定引用參數

    //有些綁定的參數我們希望以引用方式傳遞,或者時要綁定的參數的類型無法拷貝(例如:ostream類型)
    // bind只會拷貝傳給它的參數,如果我們希望傳遞給bind一個對象又不拷貝它,就必須使用標準庫ref函數
    for_each(words.begin(), words.end(),
                bind()print, ref(os), _1, ' '));
  7. 流迭代器
    (1)istream_iterator

    // 從cin讀取int,一直到eof,將輸入的值用來構造vec
    istream_iterator<int> in_iter(cin), eof;
    vector<int> vec(in_iter, eof);
    // 也可以使用算法來操作流迭代器,計算輸入的int型數字的和
    cout << accumulate(in_iter, eof, 0) << endl;

    (2)ostream_iterator

    //使用ostream_iterator來輸出值的序列,每個元素輸出後還打印出一個空格(也可以是其他字符串,但必須是C風格的)
    ostream_iterator<int> out_iter(cout, " ");
    for (auto e : vec)
        *out_iter++ = e;  //賦值語句實際上將元素寫到cout
    cout << endl;
    // 運算符*和++實際上對ostream_iterator對象那個不做任何事情,但是還是推薦這種寫法
    //調用copy來打印vec中的元素,比循環更加簡單
    copy(vec.begin(), vec.end(), out_iter);
    cout << endl;
  8. 可以調用reverse_iterator的base成員來將一個反向迭代器轉換成其對應的普通迭代器(即正向)
  9. 迭代器總共有5種,從下往上分別爲繼承關係
    (1)input iterator;
    (2)output iterator;
    (3)forward iterator;
    (4)bidirectional iterator;
    (5)random-access iterator;
//練習10.30
istream_iterator<int> in_iter(cin), eof;    
vector<int> vec(in_iter, eof);   
sort(vec.begin(), vec.end());
ostream_iterator<int> out_iter(cout, " ");
copy(vec.begin(), vec.end(), out_iter);
/*消除重複單詞,並統計長度大於sz的單詞數量*/
#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>

using namespace std;

void elimDups(vector<string> &words)
{
    sort(words.begin(), words.end());

    auto end_unique = unique(words.begin(), words.end());

    words.erase(end_unique, words.end());
}

bool isShorter(const string &s1, const string &s2)
{
    return s1.size() < s2.size();
}

//根據ctr的數值來判斷返回單詞的單數還是複數形式
string make_plural(size_t ctr, const string &word,
                               const string &ending)
{
    return (ctr > 1) ? word + ending : word;
}

void biggies(vector<string> &words,
             vector<string>::size_type sz)
{
    elimDups(words);  //按字典序排序,刪除重複單詞
    //按長度排序,長度相同的單詞維持字典序
    stable_sort(words.begin(), words.end(),
               [](const string &a, const string &b)
                  { return a.size() < b.size(); });


    //獲取一個迭代器,指向第一個滿足size() >= sz 的元素
    auto wc = find_if(words.begin(), words.end(),
                     [sz](const string &a)
                          { return a.size() >= sz; });

    //計算元素數目
    auto count = words.end() - wc;
    /* 
    //直接調用count_if,獲得滿足size()>= sz的元素個數
    auto count = count_if(words.begin(), words.end(),
                     [sz](const string &a)
                          { return a.size() >= sz; });
    */
    cout << count << " " << make_plural(count, "word", "s")
         << " of length " << sz << " or longer " << endl;

    for_each(wc, words.end(),
            [](const string &s) { cout << s <<" "; });
    cout << endl;
}
int main()
{
    vector<string> words = {"the","quick","red","fox","jumps","over","the","slow","red","turtle"};

    biggies(words, 5);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章