cpp 11&14 decltype&lambdas

  • decltype
    1
    2
    map<string,float> coll;
    decltype(coll)::value_type elem; // map<string,float>::value ele;
  • lambdas
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //mutable 关键字,表示是否可以改写
    //thorwSpec 表示可以抛出的异常
    //retType 表示返回值
    //三个都没有(parameters)可以不写
    // ^
    //[] 这个里面可以放外部的变量,不放入就看不见。可以传值和引用
    [...](parameters)mutable(opt),thorwSpec(opt)->retType(opt){
    ...
    }

    auto i=[...](parameters)mutable(opt),thorwSpec(opt)->retType(opt){
    ...
    }()//表示直接调用

decltype

获取一个表达式的类型

code

1
2
map<string,float> coll;
decltype(coll)::value_type elem; // map<string,float>::value ele;

sample

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
27
28
29
30
31
32
33
34
35
36
//**************************************//
map<string,float> coll;
decltype(coll)::value_type elem; // map<string,float>::value ele;



//**************************************//
template<typename T1,typename T2>
decltype(x+y) add(T1 x,T2 y); //表示表达式返回值的结果是x+y之后的类型,编译不过,
//改进方法
template<typename T1,typename T2>
auto add(T1 x,T2 y)->decltype(x+y); //函数返回类型的制定方式,与lambda 表达式类似



//**************************************//
template <template T>
void test18_decltype(T obj){
map<string,float>::value_type elem1;

map<string,float>coll;
decltype(coll)::value_type elem2;

typedef typename decltype(obj)::iterator iType;//等价于 typedef typename T::iterator iType
// 我知道obj 是一个容器,因此一定有iterator, 一旦使用:: 前要跟上 typename 告诉编译器后面的是一个类型的名字


//**************************************//
auto cmp=[](const Person& p1,const Person& p2){
return p1.lastname()<p2.lastname()||(p1.lastname()==p2.lastname()&&p1.firstname<p2.firstname())
}

std::set<Person,decltype(cmp)> coll(cmp);

}

lambdas

是一个对象,但是用起来像一个function
类型是一个匿名的函数对象

code

1
2
3
4
5
6
7
8
9
10
11
12
13
//mutable 关键字,表示是否可以改写
//thorwSpec 表示可以抛出的异常
//retType 表示返回值
//三个都没有(parameters)可以不写
// ^
//[] 这个里面可以放外部的变量,不放入就看不见。可以传值和引用
[...](parameters)mutable(opt),thorwSpec(opt)->retType(opt){
...
}

auto i=[...](parameters)mutable(opt),thorwSpec(opt)->retType(opt){
...
}()//表示直接调用

sample

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
//******************************
int id=0;
auto f=[id]()mutable{
std::cout<<"id:"<<id<<std<<endl;
++id;

static int x=5; //声明静态变量
int y=6;
return id; //返回数值
}
//上述表达式相当于如下代码

class Functor{
private:
int id;
public:
void operator(){
std::cout<<"id"<<id<<endl;
id++;
}
};
Functor f;

//使用
id=42;
f();
f();
f();
std::cout<<id<<std::endl;
// id:0
// id:1
// id:2
// 42
// 因为编译的时候id 已经变为0,因为[id]

//********************************
int tobefound=5l
auto lambda=[tobefound](int val){return val == tobefound;};
//上式等价于
class UnNameLocalFunction{
int localVar;
public:
UnNamedLocalFunction(int var):localVar(var){}
bool operator()(int val){
return val==localVal;
}
}
//使用
bool b1=lambda1(5);

UnNameLocalFunction lambda2(tobefound);
bool b2=lambda2(5)


//**********************
vector<int> vi{5,32,56,214,777,5543,22}
int x=30;
int y=100;
vi.erase(remove_if(vi.begin(),vi.end(),[x,y](int n){return x<n && n<y}))

for(auto i:vi)
cout<< i<<""; //5,214,777,5543
cout<<endl;

lambdas的对比

  • 类型1(值传递,mutable)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    int id=0;
    auto f=[id]()mutable{
    std::cout<<"id:"<<id<<std<<endl;
    ++id;
    }

    id=42;
    f();
    f();
    f();
    std::cout<<id<<std::endl;
    // id:0
    // id:1
    // id:2
    // 42
  • 类型2(引用传递)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    int id=0;
    auto f=[&id]()mutable{
    std::cout<<"id:"<<id<<std<<endl;
    ++id;
    }

    id=42;
    f();
    f();
    f();
    std::cout<<id<<std::endl;
    // id:42
    // id:43
    // id:44
    // 45
  • 类型3(默认全部传递,值传递)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    int id=0;
    auto f=[=]()mutable{
    std::cout<<"id:"<<id<<std<<endl;
    ++id;
    }

    id=42;
    f();
    f();
    f();
    std::cout<<id<<std::endl;
    // id:42
    // id:43
    // id:44
    // 45
  • 类型4(值传递) Error

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    int id=0;
    //编译报错,因为id为只读不可修改
    auto f=[id](){
    std::cout<<"id:"<<id<<std<<endl;
    ++id;
    }

    id=42;
    f();
    f();
    f();
    std::cout<<id<<std::endl;

注意

当我们需要知道lambadas表达式的类型时,这种情况主要被应用在传递一个函数作为hash函数或者排序函数或者排序的准则对于一个无序的容器

1
2
3
4
5
6
auto cmp=[](const Person& p1,const Person& p2){
return p1.lastname()<p2.lastname()||(p1.lastname()==p2.lastname()&&p1.firstname<p2.firstname())
}

std::set<Person,decltype(cmp)> coll(cmp);
//对于这个实现,我们需要将cmp对象传入,要不然会默认调用Compare 的默认构造函数,但是由于传入的是匿名函数,所以没有默认构造。编译会报错

原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
template<class Key,class Compare=less<Key>,
class Alloc=alloc>
class set{
public:
//typedefs:
...
typedef Compare key_compare;
typedef Compare value_compare;
private:
typedef rb_tree<key_type,value_type,
identity<value_type>,
key_compare,Alloc> rep_type;
rep_type t;
public:
...
set():t(Compare()){}
explicit set(const Compare& comp):t(comp)
}