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 
#include 
#include 
#include 

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;
}

你可能感兴趣的:(C++)