【深入理解C++11:C++新特性解析】第7章 为改变思考方式而改变 测试代码整理

目录

7-1.C++11标准中的nullptr提案的代码示例,在不同编译器情况下的不同表现

7-2.nullptr(编译时期的指针空值常量)是有类型的且仅仅可以被隐式转换成指针类型

7-3.一个例子看一下nullptr的使用方法(我的实验环境if(nullptr)和if(nullptr == 0)可通过编译,书中的g++版本是多少呢?)

7.4.实例化函数模板时nullptr并不会被编译器智能地推导成某种基本类型的指针,必须做显示的类型转换

7-5.C++中,nullptr到任何指针的转换是隐式的,而(void*)0必须经过类型转换之后才能使用

7-6.对于普通用户来说,不要对nullptr做取地址的操作,会报错

7-7.类提供了带参数版本的构造函数之后就必须自行提供不带参数的版本且此类不再是POD类型

7-8.提供带参数版本的构造函数并指示编译器提供默认版本,则本自定义类型依然是POD类型

7-9.一个禁止使用者使用拷贝构造函数的例子

7-10.使用delete同样可以禁止使用者使用拷贝构造函数

7-11.用“=default”来定义显示缺省函数

7-12.用“=delete”(显示删除)来禁止用户使用一些不该使用的类成员函数

7-13.对7-12中的例子加explicit关键字,只删除显式构造函数,隐式构造还可以完成

7-14.显式删除并不局限于缺省版本的类成员或全局函数,对于一些普通函数我们也可以通过显式删除来禁止类型转换

7-15.使用显示删除来删除自定义的operator new操作符,可以避免在堆上分配该类的对象

7.16.使用显示删除来删除析构函数来限制自定义类型在栈上或者静态的构造

7-17.一个lambda函数的简单示例

7-18.列出各种各样的lambda函数

7-19.用捕捉列表的方式来改写7-17中的例子

7-20.用[=]来声明捕捉列表,对代码7-19做进一步的简化

7-21.仿函数的一个小回顾

7-21-附近.借不同的仿函数对象的多个不同初始状态的实例产生多个功能类似却不同的仿函数实例

7-22.用仿函数和lambda表达式两种方式实现一个机场返税的场景

7-23.借不同的仿函数对象的多个不同初始状态的实例产生多个功能类似却不同的仿函数实例

7-24.由初始化状态决定的常量的例子(有警告,需要再研究这个例子)

7-25.由初始化状态决定的常量的例子

7-26.演示lambda表达式向函数指针转换的条件

7-27.演示lambda函数的常量性以及mutable关键词的含义

7-28.lambda的捕捉列表中的变量都会成为等价仿函数中的成员变量且不允许被修改

7-29.分别用 "传统的for循环","函数指针","使用lambda函数和算法for_each"三种方法来遍历一个vector,找出其中大于ubound的值

7-30.分别用"传统的for循环","仿函数","使用lambda函数和算法for_each"三种方法来遍历一个vector,找出其中大于ubound的值

7-31.通过寻找vector容器中第一个等于val的元素比较内置方案书与lambda使用上的特点

7-32.通过寻找vector nums中第一个介于[low,high)之间的元素比较内置方案书与lambda使用上的特点

7-33.试图改变vector中的内容,将vector中的所有元素都加10的一个例子

7-34.分别使用accumulate算法和lambda来实现区间统计

7-35.lambda的捕捉列表仅能捕捉父作用的自动变量,对超过这个范围中的变量是不能被捕捉的

7-36.仿函数的可访问范围比lambda大


7-1.C++11标准中的nullptr提案的代码示例,在不同编译器情况下的不同表现

#include <stdio.h>
void f(char* c){
    printf("invoke f(char*)\n");
}
void f(int i){
    printf("invoke f(int)\n");
}
int main(){
    f(0);
    /* f(NULL);
       此处如果用gcc编译会报错,
       NULL会被转化为内部标识__null,
       编译器在编译时期做了一些分析,一旦遇到二义性就停止了编译并向用户报告错误,所以该语句会编译失败,
      此处用xlC不会报错
    */
    f(NULL); 
    f((char*)0); 
    return 0;
}
/*
   编译选项:xlC -+ 7-1-1.cpp
   代码清单: 7-1
   代码功能:C++11标准中的nullptr提案的代码示例,在不同编译器情况下的不同表现
*/

7-2.nullptr(编译时期的指针空值常量)是有类型的且仅仅可以被隐式转换成指针类型

#include <stdio.h>
void f(char* c){
    printf("invoke f(char*)\n");
}
void f(int i){
    printf("invoke f(int)\n");
}
int main(){
    f(0);
    f(nullptr); 
    return 0;
}
/*
   编译选项:g++ -std=c++11 7-1-2.cpp
   代码清单: 7-2
   代码功能:nullptr是有类型的且仅仅可以被隐式转换成指针类型,在gcc和xlC下都遵循此规则
*/

7-3.一个例子看一下nullptr的使用方法(我的实验环境if(nullptr)和if(nullptr == 0)可通过编译,书中的g++版本是多少呢?)

#include <iostream>
#include <typeinfo>
using namespace std;
int main(){

   char *cp = nullptr; // nullptr可以隐式转换为char*
   //int n1 = nullptr;  //nullptr 不可以转换为整型,此处不能通过编译
   //int n2 = reinterpret_cast<int>(nullptr);// 任何类型都不能转化成nullptr_t,此处不能通过编译
   //reinterpret_cast<char*>的转换就是不理会数据本来的语义,而重新赋予它char*的语义,此处遇到连reinterpret_cast都无法强转的类型
   nullptr_t nptr;// nullptr_t类型变量可以用==,<=,>=符号与nullptr作比较,nullptr是nullptr_t这种数据类型的一个变量
   if(nptr == nullptr)
       cout<< "null_ptr nptr == nullptr" << endl;
    else
       cout<< "null_ptr nptr != nullptr" << endl;
    if(nptr < nullptr)
       cout<< "null_ptr nptr < nullptr" << endl;
    else
       cout<< "null_ptr nptr !<  nullptr" << endl;
    // 书上说这里不能编译通过,我的g++编译通过了
    if(0 == nullptr) {
        cout<< "0 == null_ptr is true" << endl;
    }
    else{
        cout<< "0 == null_ptr is false" << endl;

    }
    // 书上也说这里不能编译通过,我的g++也编译通过了
    if(nullptr){
        cout<<  "if(null_ptr) is true" << endl;
    }
    else{
        cout << "if(nullptr) is false" <<endl;
    }

    //nullptr += 1; // 不可以进行算术运算,此处不能编译通过
    //nullptr * 5;  // 不可以进行算术运算,此处不能编译通过
    sizeof(nullptr);
    typeid(nullptr);
    throw(nullptr);
    return 0;
}

/*
   编译选项:g++ -std=c++11 7-1-3.cpp
   代码清单: 7-3
   代码功能:一个例子看一下nullptr的使用方法(我的实验环境与书上部分有出入)
*/

gcc官网

7.4.实例化函数模板时nullptr并不会被编译器智能地推导成某种基本类型的指针,必须做显示的类型转换

#include <iostream>
using namespace std;
template<typename T> void g(T* t){cout << "function g" << endl;}
template<typename T> void h(T  t){cout << "function h" << endl;}

int main(){
    // g(nullptr);      // 编译失败,nullptr的类型是nullptr_t,不是指针,调用必须要显示转换
    g((float*)nullptr); // 推导出T = float
    h(0);               // 推导出T = int
    h(nullptr);         // 推导出T = nullptr_t
    h((float*)nullptr); // 推导出T = float*
    return 0;
}
/*
   编译选项:g++ -std=c++11 7-1-4.cpp
   代码清单: 7-4
   代码功能:实例化函数模板时nullptr并不会被编译器智能地推导成某种基本类型的指针,必须做显示的类型转换
*/

7-5.C++中,nullptr到任何指针的转换是隐式的,而(void*)0必须经过类型转换之后才能使用

int foo()
{
  int* px = (void*)0;// 编译错误,C++中不能隐式地将无类型指针转换成int*类型的指针, int* px = (int*)(void*)0;可以通过编译
  int* py = nullptr;
  return 0;
}
/*
   编译选项:g++ -std=c++11 7-1-5.cpp -c
   代码清单: 7-5
   代码功能:C++中,nullptr到任何指针的转换是隐式的,而(void*)0必须经过类型转换之后才能使用
*/

7-6.对于普通用户来说,不要对nullptr做取地址的操作,会报错

#include <cstdio>
#include <cstddef>
using namespace std;
int main(){
    nullptr_t my_null;
    printf("%x \n",&my_null);
   // printf("%x \n",&nullptr);// C++11的标准规定,用户不可对nullptr取地址,本句无法编译通过
    printf("%d \n",my_null == nullptr);
    const nullptr_t && default_nullptr = nullptr;// default_nullptr是nullptr的一个右值引用
    printf("%x\n",&default_nullptr);
}
/*
   编译选项:g++ -std=c++11 7-1-6.cpp 
   代码清单: 7-6
   代码功能:对于普通用户来说,不要对nullptr做取地址的操作,会报错
*/

7-7.类提供了带参数版本的构造函数之后就必须自行提供不带参数的版本且此类不再是POD类型

#include <type_traits>
#include <iostream>
using namespace std;
class TwoCstor{
    public:
        /*
         提供了带参数版本的构造函数之后就必须自行提供不带参数的版本,
         且TwoCstor不再是POD类型
        */
        TwoCstor(){};
        TwoCstor(int i):data(i){};
    private:
        int data;
};
int main(){
    cout << is_pod<TwoCstor>::value <<endl;
}

/*
   编译选项:g++ -std=c++11 7-2-1.cpp 
   代码清单: 7-7
   代码功能:类提供了带参数版本的构造函数之后就必须自行提供不带参数的版本且此类不再是POD类型
*/

7-8.提供带参数版本的构造函数并指示编译器提供默认版本,则本自定义类型依然是POD类型

#include <type_traits>
#include <iostream>
using namespace std;
class TwoCstor{
    public:
        /*
         提供了带参数版本的构造函数之后再指示编译器提供默认版本,
         则本自定义类型依然是POD类型
        */
        TwoCstor(){};
        TwoCstor(int i):data(i){};
    private:
        int data;
};
int main(){
    cout << is_pod<TwoCstor>::value <<endl;
}

/*
   编译选项:gcc -std=c++11 7-2-2.cpp 
   代码清单: 7-8
   代码功能:提供了带参数版本的构造函数之后再指示编译器提供默认版本,则本自定义类型依然是POD类型
*/

7-9.一个禁止使用者使用拷贝构造函数的例子

#include <type_traits>
#include <iostream>
using namespace std;
class NoCopyCstor{
  public:
      NoCopyCstor() = default;
  private:
      /*
      将拷贝构造函数声明为private成员并不提供实现可以有效地阻止用户
      错用拷贝构造函数,这个是流氓啊
      */
      NoCopyCstor(const NoCopyCstor&);
};
int main(){
   NoCopyCstor a;
   NoCopyCstor b(a); // 无法通过编译
   return 0;
}
/*
   编译选项:g++ -std=c++11 7-2-3.cpp 
   代码清单: 7-9
   代码功能:将拷贝构造函数声明为private成员并不提供实现可以有效地阻止用户错用拷贝构造函数
*/

7-10.使用delete同样可以禁止使用者使用拷贝构造函数

#include <type_traits>
#include <iostream>
using namespace std;
class NoCopyCstor{
  public:
      NoCopyCstor() = default;
  private:
      /*
      使用“=delete”同样可以有效地阻止用户
      错用拷贝构造函数
      */
      NoCopyCstor(const NoCopyCstor&) = delete;
};
int main(){
   NoCopyCstor a;
   NoCopyCstor b(a); // 无法通过编译
   return 0;
}
/*
   编译选项:g++ -std=c++11 7-2-4.cpp 
   代码清单: 7-10
   代码功能:使用“=delete”同样可以有效地阻止用户错用拷贝构造函数
   注意点:一旦缺省版本被删除了,重载该函数也是非法的.
*/

7-11.用“=default”来定义显示缺省函数

class DefaultOptr{
   public:
      // 使用“= default”来产生缺省版本
      DefaultOptr() = default;
      DefaultOptr & operator = (const DefaultOptr &);
};
// 在类定义外用“= default”来指明使用缺省版本
inline DefaultOptr & 
DefaultOptr::operator =(const DefaultOptr &) = default;
/*
   编译选项:g++ -std=c++11 7-2-5.cpp -c
   代码清单: 7-11
   代码功能:用“=default”来定义显示缺省函数
*/

7-12.用“=delete”(显示删除)来禁止用户使用一些不该使用的类成员函数

class ConvType{
   public:
      ConvType(int i){};
      ConvType(char c) = delete;
};
void Func(ConvType ct){}
int main(){
   Func(3);
   Func('a');
   ConvType ci(3);
   ConvType cc('a');
   return 0;
}

/*
   编译选项:g++ -std=c++11 7-2-6.cpp
   代码清单: 7-12
   代码功能:用“=delete”(显示删除)来禁止用户使用一些不该使用的类成员函数
*/

7-13.对7-12中的例子加explicit关键字,只删除显式构造函数,隐式构造还可以完成

class ConvType{
   public:
      ConvType(int i){};
      explicit ConvType(char c) = delete; // 删除显式的char版本
};
void Func(ConvType ct){}
int main(){
   Func(3);
   Func('a');       // 对应显式构造函数被删除了,隐式构造还是能完成,不会报错
   ConvType ci(3);
   ConvType cc('a');  // 对应构显式造函数被删除了,此处无法完成构造了,编译报错
   return 0;
}

/*
   编译选项:g++ -std=c++11 7-2-6.cpp
   代码清单: 7-12
   代码功能:对7-12中的例子加explicit关键字,只删除显式构造函数,隐式构造还可以完成
*/

7-14.显式删除并不局限于缺省版本的类成员或全局函数,对于一些普通函数我们也可以通过显式删除来禁止类型转换

void Func(int i){};
void Func(char c) = delete; // 显示删除char版本
int main(){
   Func(3);
   Func('c'); // 本句话无法通过编译
   return 0;
}

/*
   编译选项:g++ -std=c++11 7-2-8.cpp
   代码清单: 7-14
   代码功能:显式删除并不局限于缺省版本的类成员或全局函数,对于一些普通函数我们也可以通过显式删除来禁止类型转换
*/

7-15.使用显示删除来删除自定义的operator new操作符,可以避免在堆上分配该类的对象

#include <cstddef>
class NoHeapAlloc{
    public:
       void * operator new(std::size_t) = delete;
};
int main(){
    NoHeapAlloc nha;
    NoHeapAlloc *pnha = new NoHeapAlloc; // 编译失败
    return 1;
}

/*
   编译选项:g++ -std=c++11 7-2-9.cpp
   代码清单: 7-15
   代码功能:使用显示删除来删除自定义的operator new操作符,可以避免在堆上分配该类的对象
*/

7.16.使用显示删除来删除析构函数来限制自定义类型在栈上或者静态的构造

#include <cstddef>
#include <new>
extern void* p;
class NoStackAlloc{
    public:
       ~NoStackAlloc() = delete;
};
static NoStackAlloc nhb;
int main(){
    NoStackAlloc nsa;
    new (p) NoStackAlloc();
    return 1;
}
/*
   编译选项:g++ -std=c++11 7-2-10.cpp
   代码清单: 7-16
   代码功能:使用显示删除来删除析构函数来限制自定义类型在栈上或者静态的构造
   (编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性.若析构函数不可访问,则不能在栈上创建对象)
*/

7-17.一个lambda函数的简单示例

int main(){
    int girls = 3,boys = 4;
    auto totalChild = [](int x,int y){return x+y;};
    return  totalChild(girls,boys);
}
/*
   编译选项:g++ -std=c++11 7-3-1.cpp
   执行:./a.out
        echo $?(返回7)
   代码清单: 7-17
   代码功能:一个lambda函数的简单示例
*/

7-18.列出各种各样的lambda函数

C++中的mutable推荐读链接-谢谢作者

int main(){
   []{}; // 最简单的lambda函数
   int a = 3;
   int b = 4;
   [=]{return a+b;}; // 省略了参数列表与返回类型,返回类型由编译器推断为int
   auto fun1 = [&](int c){b = a+c;}; // 省略了返回类型,无返回值
   auto fun2 = [=&b](int c)->int{return b +=a+c;}; // 各部分都很完整的lambda函数
}
/*
   编译选项:g++ -std=c++11 7-3-2.cpp
   代码清单: 7-18
   代码功能:列出各种各样的lambda函数
*/

7-19.用捕捉列表的方式来改写7-17中的例子

int main(){
    int girls = 3,boys = 4;
    auto totalChild = [girls,&boys]()->int{return girls+boys;};
    return  totalChild();
}

/*
   编译选项:g++ -std=c++11 7-3-3.cpp
   执行:./a.out
        echo $?(返回7)
   代码清单: 7-19
   代码功能:用捕捉列表的方式来改写7-17中的例子
*/

7-20.用[=]来声明捕捉列表,对代码7-19做进一步的简化

/*
   编译选项:g++ -std=c++11 7-3-3.cpp
   执行:./a.out
        echo $?(返回7)
   代码清单: 7-20
   代码功能:用[=]来声明捕捉列表,对代码7-19做进一步的简化
*/

7-21.仿函数的一个小回顾

class _functor{
  public:
      int operator()(int x,int y){return x+y;}
};
int main(){
    int girls = 3,boys = 4;
    _functor totalChild;
    return totalChild(5,6);
}
/*
   编译选项:g++ -std=c++11 7-3-5-1.cpp
   执行:./a.out
        echo $?(返回11)
   代码清单: 7-21
   代码功能:仿函数的一个小回顾
*/

7-21-附近.借不同的仿函数对象的多个不同初始状态的实例产生多个功能类似却不同的仿函数实例

#include <iostream>
using namespace std;
class Tax{
private:
       float rate;
       int base;
public:
       Tax(float r,int b):rate(r),base(b){}
       float operator()(float money){return (money-base)*rate;}
};
int main(){
     Tax high(0.40,30000);
     Tax middle(0.25,20000);
     cout << "tax over 3w:" <<high(37500)<<endl;
     cout << "tax over 2w:" <<high(27500)<<endl;
     return 0;
}
/*
   编译选项:g++ -std=c++11 7-3-5-2.cpp
   代码清单: 7-21-附近
   代码功能:借不同的仿函数对象的多个不同初始状态的实例产生多个功能类似却不同的仿函数实例
*/

7-22.用仿函数和lambda表达式两种方式实现一个机场返税的场景

class AirportPrice{
   private:
      float _dutyfreerate;
   public:
      AirportPrice(float rate):_dutyfreerate(rate){}
      float operator()(float price){
          return price*(1-_dutyfreerate/100);
      }
};
int main(){
    float tax_rate = 5.5f;
    AirportPrice Changi(tax_rate);
    auto Changi2 = [tax_rate](float price)->float{return price*(1-tax_rate/100);};
    float purchased = Changi(3699);
    float purchased2 = Changi2(2899);
    return 0;
}
 /*
   编译选项:g++ -c -std=c++11 7-3-6.cpp
   代码清单: 7-22
   代码功能:用仿函数和lambda表达式两种方式实现一个机场返税的场景
*/

7-23.借不同的仿函数对象的多个不同初始状态的实例产生多个功能类似却不同的仿函数实例

extern int z;
extern float c;
void Calc(int&,int,float&,float);
void TesCalc(){
   int x, y = 3;
   float a,b = 4.0;
   int success = 0;
   auto validate = [&]()->bool{ // [&]表示引用传递捕捉所有父作用域的变量,包括this
       if((x=y+z)&&(a==b+c))
          return 1;
        else
          return 0;   
   };
   Calc(x,y,a,b);
   success += validate();
   y = 1024;
   b = 1e13;
   Calc(x,y,a,b);
   success += validate();
 }
 /*
   编译选项:g++ -c -std=c++11 7-3-7.cpp
   代码清单: 7-23
   代码功能:借不同的仿函数对象的多个不同初始状态的实例产生多个功能类似却不同的仿函数实例
*/

7-24.由初始化状态决定的常量的例子(有警告,需要再研究这个例子)

int Prioritize(int);
int AllWorks(int times){
   int i;
   int x;
   try{
      for(int i ;i<times;i++){
        x += Prioritize(i);
      }
   }
   catch(...){
      x = 0;
   }
   const int y = [=]{
       int i,val;
       try{
         for(i = 0;i<times;i++){
            val += Prioritize(i);
         }
       }
       catch(...){
           val = 0;
       }
       return val;
   }();// 疑问:这里加()是做什么的呢?
}
 /*
   编译选项:g++ -c -std=c++11 7-3-8.cpp
   代码清单: 7-24
   代码功能:由初始化状态决定的常量的例子(有警告,需要再研究这个例子)
*/
// [capture](parameters)mutable->return-type{statements}

7-25.由初始化状态决定的常量的例子

#include <iostream>
using namespace std;
int main(){
   int j = 12;
   auto by_val_lambda = [=]{return j+1;};
   auto by_ref_lambda = [&]{return j+1;};
   cout << "by_val_lambda:" << by_val_lambda()<<endl; // 13
   cout << "by_ref_lambda:" << by_ref_lambda()<<endl; // 13
   j++;
   cout << "by_val_lambda:" << by_val_lambda()<<endl; // 13
   cout << "by_ref_lambda:" << by_ref_lambda()<<endl; // 14
   return 0;
}

 /*
   编译选项:g++ -std=c++11 7-3-9.cpp
   代码清单: 7-25
   代码功能:由初始化状态决定的常量的例子
*/
/*
第一次调用by_val_lambda和by_ref_lambda时,其运算结果并没有不同。
两者均计算的是12+1=13。但在第二次调用by_val_lambda的时候,其计算
的是12+1=13,相对地,第二次调用by_ref_lambda时计算的是13+1=14。
这个结果的原因是由于在by_val_lambda中,j被视为了一个常量,一旦初
始化后不会再改变(可以认为之后只是一个跟父作用域中j同名的常量)而
在by_ref_lambda中,j仍在使用父作用域中的值。
*/

7-26.演示lambda表达式向函数指针转换的条件

int main(){
    int girls = 3,boys = 4;
    auto totalChild = [](int x,int y)->int{return x+y;};
    typedef int(*allchild)(int x,int y); 
    typedef int(*onechild)(int x); 
    allchild p;
    p = totalChild;
    onechild q;
   //q = totalChild; // 编译失败,参数必须一致
    decltype(totalChild) allPeople = totalChild; // 需要通过decltype获得lambda的类型
   //decltype(totalChild) totalChild = p;  // 编译失败,指针无法转换为lambda       
    return 0;
}

 /*
   编译选项:g++ -std=c++11 7-3-10.cpp
   代码清单: 7-26
   代码功能:演示lambda表达式向函数指针转换的条件:
            (1)lambda函数没有捕捉变量;
            (2)函数指针必须要与此lambda函数有相同的调用方式.
*/

7-27.演示lambda函数的常量性以及mutable关键词的含义

int main(){
    int val;
    auto const_val_lambda = [=](){val = 3;}; //  编译失败,lambda函数默认是const的,这里却出现在const的lambda中修改常量的情况
    auto mutable_val_lambda = [=]()mutable{ val = 3;}; // 编译成功,在非const的lambda函数中,可以修改常量数据
    auto const_ref_lambda = [&]{val = 3;};   //  编译成功,依然是const的lambda,这里没有改动引用本身,可以通过编译
    auto const_param_lambda = [&](int  v){ v = 3;}; //编译成功,const的lambda,通过参数传递val
    const_param_lambda(val);// 编译成功
    return 0;
}


 /*
   编译选项:g++ -std=c++11 7-3-11.cpp
   代码清单: 7-27
   代码功能:演示lambda函数的常量性以及mutable关键词的含义
*/

7-28.lambda的捕捉列表中的变量都会成为等价仿函数中的成员变量且不允许被修改

class const_val_lambda{
   public:
       const_val_lambda(int v ):val(v){}
    public:
       void operator()()const{val = 3;}/*这里编译会报错,这里是常量成员函数却对val的值做了修改*/
    private:
       int val;
};
 /*
   编译选项:g++ -std=c++11 7-3-12.cpp
   代码清单: 7-28
   代码功能:lambda的捕捉列表中的变量都会成为等价仿函数中的成员变量且不允许被修改
*/

7-29.分别用 "传统的for循环","函数指针","使用lambda函数和算法for_each"三种方法来遍历一个vector,找出其中大于ubound的值

#include <vector>
#include <algorithm>
using namespace std;
vector<int> nums;
vector<int> largeNums;
const int ubound = 10;
inline void LargeNumsFunc(int i){
    if(i > ubound)
         largeNums.push_back(i);
}
void Above(){
    // 传统的for循环
    for(auto itr = nums.begin(); itr != nums.end();++itr){
        if(*itr >= ubound)
            largeNums.push_back(*itr);   
    }

    // 使用函数指针
    for_each(nums.begin(),nums.end(),LargeNumsFunc);
    
    // 使用lambda函数和算法for_each
    for_each(nums.begin(),nums.end(),[=](int i){
          if(i>ubound)
            largeNums.push_back(i);
    });
}
 /*
   编译选项:g++ 7-3-13.cpp -c -std=c++11 
   代码清单: 7-29
   代码功能:分别用 "传统的for循环","函数指针","使用lambda函数和算法for_each"三种方法来遍历一个vector,找出其中大于ubound的值
*/

7-30.分别用"传统的for循环","仿函数","使用lambda函数和算法for_each"三种方法来遍历一个vector,找出其中大于ubound的值

#include <vector>
#include <algorithm>
using namespace std;
vector<int> nums;
vector<int> largeNums;
const int ubound = 10;
class LNums{
    public:
        LNums(int u):ubound(u){}
        void operator()(int i) const{
             if(i>ubound)
                largeNums.push_back(i);
        }
    private:
        int ubound;
};
void Above(){
    // 传统的for循环
    for(auto itr = nums.begin(); itr != nums.end();++itr){
        if(*itr >= ubound)
            largeNums.push_back(*itr);   
    }

    // 使用仿函数
    for_each(nums.begin(),nums.end(),LNums(ubound));
    
    // 使用lambda函数和算法for_each
    for_each(nums.begin(),nums.end(),[=](int i){
          if(i>ubound)
            largeNums.push_back(i);
    });
}
 /*
   编译选项:g++ -std=c++11 7-3-14.cpp -c
   代码清单: 7-30
   代码功能:分别用"传统的for循环","仿函数","使用lambda函数和算法for_each"三种方法来遍历一个vector,找出其中大于ubound的值
*/

7-31.通过寻找vector容器中第一个等于val的元素比较内置方案书与lambda使用上的特点

#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
extern vector<int> nums;
void OneCon(int val){
    // 传统的for循环
   for(auto i = nums.begin();i!=nums.end();i++)
        if(*i == val) break;
    // 使用内置的仿函数(template)equal_to,通过bind2nd使其成为但参数调用的仿函数
    find_if(nums.begin(),nums.end(),bind2nd(equal_to<int>(),val));
    // 使用lambda函数
    find_if(nums.begin(),nums.end(),[=](int i){return i == val;});
}

 /*
   编译选项:g++ -std=c++11 7-3-15.cpp -c
   代码清单: 7-31
   代码功能: 通过寻找vector容器中第一个等于val的元素比较内置仿函数与lambda使用上的特点
*/

7-32.通过寻找vector nums中第一个介于[low,high)之间的元素比较内置方案书与lambda使用上的特点

#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
extern vector<int> nums;
void TwoCond(int low,int high){

    // 传统的for循环 
   for(auto i = nums.begin();i!=nums.end();i++)
        if(*i == val) break;
    // 利用了3个内置的仿函数,以及非标准的compose2
    find_if(nums.begin(),nums.end(),compose2(logical_and<bool>(),bin2nd(less<int>(),high),bin2nd(greater_equal<int>(),low)));
    // 使用lambda函数
    find_if(nums.begin(),nums.end(),[=](int i){return i>= low && i < high;});
}
 
/*
   编译选项:g++ -std=c++11 7-3-16.cpp -c
   代码清单: 7-32
   代码功能: 通过寻找vector nums中第一个介于[low,high)之间的元素比较内置仿函数与lambda使用上的特点
*/

7-33.试图改变vector中的内容,将vector中的所有元素都加10的一个例子

#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
vector<int> nums;
void Add(const int val){
    auto print = [&]{
        for(auto s:nums){cout << s << '\t';}
        cout <<endl;
    };  
    // 传统的for循环 
    for(auto i = nums.begin();i!=nums.end();++i){
        *i = *i + val;
    }   
    print();
    // 试一试for_each及内置函数
    for_each(nums.begin(),nums.end(),bind2nd(plus<int>(),val));
    print();

    // 实际这里需要使用STL的一个变动性算法:transform
    transform(nums.begin(),nums.end(),nums.begin(),bind2nd(plus<int>(),val));
    print();

    // 不过再lambda的支持下,我们还可以只使用for_each
    for_each(nums.begin(),nums.end(),[=](int &i){ i += val;});
    print();
}
int main(){
    for(int i = 0;i< 10;i++){
        nums.push_back(i);
    }   
    Add(10);
    return 1;
}
/*
   编译选项:g++ -std=c++11 7-3-17.cpp -c
   代码清单: 7-33
   代码功能: 通过寻找vector nums中每个元素都加10的例子比较内置仿函数与lambda使用上的特点
*/

7-34.分别使用accumulate算法和lambda来实现区间统计

#include <numeric>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
void Stat(vector<int> &v){
    int errors;
    int score;
    auto print =[&]{
        cout << "Errors:" <<errors <<endl << "Score:" << score << endl;
    };  
    // 使用accumulate算法,需要两次循环
    errors = accumulate(v.begin(),v.end(),0);
    score = accumulate(v.begin(),v.end(),100,minus<int>());
    print();
    errors = 0;
    score = 100;
    // 使用lambda就只需要一次循环
    for_each(v.begin(),v.end(),[&](int i){ 
        errors += i;
        score -= i;
    }); 
    print();
}
int main(){
    vector<int> v(10);
    generate(v.begin(),v.end(),[]{
        return rand()%10;
    }); 
    Stat(v);
    return 0;
}

7-35.lambda的捕捉列表仅能捕捉父作用的自动变量,对超过这个范围中的变量是不能被捕捉的

int d = 0;
int TryCapture(){
    auto ill_lambda = [d]{};
    return 0;
}

/*
   编译选项:g++ -std=c++11 7-3-19.cpp -c
   代码清单: 7-35
   代码功能: lambda的捕捉列表仅能捕捉父作用的自动变量,对超过这个范围中的变量是不能被捕捉的
*/

7-36.仿函数的可访问范围比lambda大

int d = 0;
class healthyFunctor{
    public:
       healthyFunctor(int d):data(d){}
       void operator()()const{}
    private:
       int data;
};
int TryCapture(){
    healthyFunctor hf(d);
    return 0;
}
/*
   编译选项:g++ -std=c++11 7-3-20.cpp -c
   代码清单: 7-36
   代码功能: 仿函数的可访问范围比lambda大
*/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值