不落辰

知不可乎骤得,托遗响于悲风

0%

概述

  • bind和function 极常用!!
  • bind1st:operator()的第一个形参绑定成一个确定的值
  • bind2nd:operator()的第二个形参绑定成一个确定的值
  • c++11从boost库引入了bind绑定器和function函数对象机制
  • lambda表达式:底层依赖函数对象的机制实现

bind1st、bind2nd(弃用)。bind更好用

  • 绑定器+二元函数对象 -> 一元函数对象

    例子

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
int main()
{
vector<int> vec;
srand(time(nullptr));
for (int i = 0; i < 20 ; ++i)
{
vec.push_back(rand() % 100 + 1);
}
showContainer(vec);
sort(vec.begin(), vec.end()); // 默认小到大排序
showContainer(vec);

// 找第一个小于70的数字
// operator()(const T &val)
// greater a > b
// less a < b
// 绑定器 + 二元函数对象 =》 一元函数对象
// bind1st: + greater bool operator()(70, const _Ty& _Right)
// bind2nd: + less bool operator()(const _Ty& _Left, 70)
auto it1 = find_if(vec.begin(), vec.end(),
bind1st(less<int>(), 70));
cout<<*it1<<endl;
}
28 21 82 75 89 90 7 4 82 79 57 31 41 91 58 38 74 63 63 9
4 7 9 21 28 31 38 41 57 58 63 63 74 75 79 82 82 89 90 91
74

原理

  • bind1st底层原理
    • bind1st -> _bind1st
      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
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      //
      // Created by dell on 2022/3/18.
      // 手写bind1st、bind2nd、my_find_if

      template<typename Container>
      void showContainer(Container & con)
      {
      // Container作为一个模板类型参数,当编译器遇到Container::mem这样的代码时,他不会知道mem是一个类型成员还是一个static数据成员,
      // 直至实例化时才会知道。但是,为了处理模板,编译器必须知道名字是否表示一个类型。
      // 默认情况下,C++假定通过作用域运算符::访问的名字不是类型。因此,如果我们希望使用一个模板类型参数的类型成员,就必须显示告诉编译器改名字是一个=类型。我们通过使用typename来实现这一点。
      // typename:明确指出iterator是一个类型而非static数据成员。
      typename Container::iterator iter = con.begin();
      for(;iter!=con.end();++iter)
      {
      cout<<*iter<<" ";
      }
      cout<<endl;
      }


      // 函数模板怎么匹配的???Iterator和谁匹配??
      // 函数模板可以进行类型推演:根据我们传入的实参,可以把模板类型推演出来
      template<typename Iterator,typename Compare>
      Iterator my_find_if(Iterator first,Iterator last,Compare cmp)
      {
      for( ; first!=last;++first)
      {
      if(cmp(*first))
      {
      return first;
      }
      }
      return first;
      }


      // 重载(),真正的一元函数对象
      // 封装,真正做事情的还是那个二元函数
      template<typename Compare,typename T>
      class _mybind1st
      {
      public:
      _mybind1st(Compare cmp,const T& t):_cmp(cmp),_val(t){}
      bool operator()(const T& second) // 要传入的参数(非绑定参数)
      {
      return _cmp(_val,second); // 绑定了第一个参数的二元函数
      }
      private:
      Compare _cmp; // 二元函数
      T _val; // 绑定的那个参数
      };

      // 函数模板:封装了一元对象的产生。
      // 就是个中转站。传入函数和要绑定的参数。返回绑定完的一元函数对象。
      // 函数模板作用:让用户无需指明类,直接传参数即可。如果直接用_mybind1st的话,则需要自己指明模板参数类型
      // 使用函数模板:好处是可以进行类型推演。根据我们传入的实参,可以把模板类型推演出来。
      template<typename Compare,typename T>
      _mybind1st<Compare,T> mybind1st(Compare cmp,const T& val)
      {
      return _mybind1st<Compare,T>(cmp,val); // 生成一元函数对象
      }


      int main()
      {
      vector<int> v;
      srand(time(nullptr));
      for(int i=0;i<10;++i)
      {
      v.push_back(rand()%100);
      }

      showContainer(v);
      sort(v.begin(),v.end(),greater<int>());
      showContainer(v);
      vector<int>::iterator iter = my_find_if(v.begin(),v.end(), mybind1st(greater<int>(),70));
      cout<<*iter<<endl;
      }

      58 82 80 86 74 69 79 22 68 60
      86 82 80 79 74 69 68 60 58 22
      86 82 80 79 74 69 68 60 58 22
      69

function

用途:建立函数表

  • 把所用的函数、绑定器、函数对象、lambda表达式的类型表达起来,否则绑定器和lambda表达式只能存在于语句之中,在其他语句还要重写绑定器和lambda表达式。
  • 作用:建立函数表。switch不满足开闭原则,我们建立map<int,function<void(void)>>函数表来替代
    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

    #include<unordered_map>

    void doShow(){cout<<"查看所有书籍"<<endl;}
    void doBorrow(){cout<<"借书"<<endl;}
    void doBack(){cout<<"还书"<<endl;}

    int main()
    {
    //如果用函数指针如 void(*)(void) 则second只能接受普通的全局函数。不能接受函数对象(如bind绑定器返回的函数对象;如函数对象类(仿函数)的对象)
    unordered_map<int,function<void(void)>> actionMap;
    actionMap.insert(std::make_pair(1,doShow));
    actionMap.insert({2,doBack});
    actionMap.insert({3,doBorrow});
    while(1)
    {
    int choice;
    cout<<"choice is"<<endl;
    cin>>choice;
    if(actionMap.find(choice)!=actionMap.end())
    {
    actionMap[choice]();
    }
    else
    {
    cout<<"no choice"<<endl;
    }
    }
    }

“渔夫在无法捕鱼时,就会修补他的网,在这段看似停滞不前的日子里,你可以休息但不要什么都不做”

完全特例化和部分特例化

  • 必须先有个泛化的,然后才能有部分和全部特例化

  • 泛化、特例化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //  泛化
    template<typename T>
    class B { }
    // 就相当于 template<typename T> class B<T>{}

    template<typename R,typename A>
    class B<R(A)> { }
    // class A<内容> <>中的内容,就是这个类在实例化时,<>钟要填入的东西的类型!
    // 通过我们填入的东西,解析出R、A这两个模板参数分别是什么
    // 如 B<int(int)> b(show) 就是 R:int 。A:int


    int show(int a){ cout<<a<<endl;}
  • 例子

    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
    64
    65
    66
    67
    68

    /*
    * 完全特例化和部分特例化
    */

    #include<iostream>

    using namespace std;

    #if 0
    template<typename Ty>
    class Vector
    {
    public:
    Vector(){cout<<"class Vector"<<endl;}
    };


    // 针对指针提供的部分特例化
    template<typename Ty>
    class Vector<Ty*>
    {
    public:
    Vector(){cout<<"class Vector<Ty*>"<<endl;}
    };

    // 针对函数指针(有返回值,两个形参变量)提供的部分特例化
    // 这三个合起来共同定义了一个类型 R(*)(A1,A2)
    template<typename R,typename A1,typename A2>
    class Vector<R(*)(A1,A2)>
    {
    public:
    Vector(){cout<<"class Vector<R(*)(A1,A2)"<<endl;}
    };

    // 针对char*提供的完全特例化
    template<>
    class Vector<char*>
    {
    public:
    Vector(){cout<<"class Vector<char*>"<<endl;}
    };

    // 针对函数提供的部分特例化
    template<typename Ty,typename R1,typename R2>
    class Vector<Ty(R1,R2)>
    {
    public:
    Vector(){cout<<"class Vector<Ty(R1,R2)>"<<endl;}
    };


    int main()
    {
    Vector<int> v1;
    Vector<int*> v2;
    Vector<char*> v3;
    Vector<int(*)(int,int)> v4;
    Vector<int(int,int)> v5;
    }
    #endif

    E:\Code\CLionCode\project02\cmake-build-debug\project02.exe
    class Vector
    class Vector<Ty*>
    class Vector<char*>
    class Vector<R(*)(A1,A2)
    class Vector<Ty(R1,R2)>

typeid坑

1
2
3
4
5
6
7
8
9
10
gcc就是那样的,只输出类型名的第一个字符,要输出完整的名字可以这样:
#include <iostream>
#include <typeinfo>
#include <cxxabi.h> //使用abi
using namespace std;
int main()
{
cout<<abi::__cxa_demangle(typeid(int).name(),0,0,0 )<<endl;
return 0;
}

模板实参推演

  • 非常非常强大的功能
  • 将一个大类型(一个函数模板参数) 使用多个模板参数 拆分成多个小类型。便于使用
    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
    int sum(int a,int b){}
    class Test
    {
    public:
    int sum(int a,int b){}
    };

    /*
    * 模板的实参推演 =》基本概念很简单
    */

    // T包含了所有的大的类型,返回值,所有形参的类型都取出来。
    template<typename T >
    void func(T t)
    {
    cout<<abi::__cxa_demangle(typeid(t).name(),0,0,0 )<<endl;
    }

    // 将类型拆开 即将上面的 函数指针类型T 拆成 返回类型R 参数类型A1 A2组成的
    template<typename R,typename A1,typename A2>
    void func2(R(*a)(A1,A2))
    {
    cout<<abi::__cxa_demangle(typeid(R).name(),0,0,0 )<<endl;
    cout<<abi::__cxa_demangle(typeid(A1).name(),0,0,0 )<<endl;
    cout<<abi::__cxa_demangle(typeid(A2).name(),0,0,0 )<<endl;
    }
    // 返回值 类类型 参数类型
    template<typename R,typename T,typename A1,typename A2>
    void func3(R(T::*t)(A1,A2)) // T:: 。怎么写,看typeid.name()就知道了
    {
    cout<<abi::__cxa_demangle(typeid(R).name(),0,0,0 )<<endl;
    cout<<abi::__cxa_demangle(typeid(T).name(),0,0,0 )<<endl;
    cout<<abi::__cxa_demangle(typeid(A1).name(),0,0,0 )<<endl;
    cout<<abi::__cxa_demangle(typeid(A2).name(),0,0,0 )<<endl;
    }


    int main()
    {
    func(sum);
    func2(sum);
    cout<<endl;
    func(&Test::sum);
    func3(&Test::sum);
    }


    int (*)(int, int)
    int
    int
    int

    int (Test::*)(int, int)
    int
    Test
    int
    int

function底层原理

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

/*
* function 底层原理
*/

#include<iostream>

using namespace std;

// 得有泛化,才能有部分/全部特例化!!!
template<typename Ty>
class Myfunction{}; // 默认泛化的是:class Myfunction<Ty>

template<typename R,typename... A>
class Myfunction<R(A...)> // void(void) ; int(int,int)... 这里就是我们用户在使用这个类时,<>所放的东西
// 通过class Myfunction<内容> 内容,和实例化时Myfunction<int(int,int)>以及传入的实参,来解析出这个类的模板参数都是什么
{
public:
using PFUNC = R(*)(A...);
Myfunction(PFUNC pfunc):_pfunc(pfunc){}
R operator()(A... args){
return _pfunc(args...);
}
private:
PFUNC _pfunc;
};

void show()
{
std::cout<<"show"<<std::endl;
}

int sum(int a ,int b)
{
return a + b;
}

int main()
{
Myfunction<int(int,int)> f2(sum);
cout<<sum(1,2)<<endl;

Myfunction<void(void)> f(show);
f();
}

// terminal
3
show

bind

bind例子

  • bind参数?
  • std::bind(待绑定的函数对象/函数指针/成员函数指针,参数绑定值1,参数绑定值2,...,参数绑定值n);
  • 参数一:函数对象/函数指针。(如果是临时对象的话,则不需要取地址)
  • 其余参数:函数列表中的参数
  • 如果有不想绑定的参数,那么需要用placeholder::_x 来占位,不能略过!!
  • hh1hh2

    bind的第一个参数是待绑定的函数对象或者函数指针,之后跟随多个参数以设定待绑定函数的参数绑定方式。待绑定函数有多少个参数,则bind后便需要多少个参数以一一声明其参数的绑定方法.当参数绑定为某一固定值时,则其对应参数绑定值可以使一个变量或常量.当需要将参数与绑定所生成的函数对象的某个参数相关联时,则需要用到在标准中预定义的几个常量_1、_2、_3等.这些常量声明在std::placeholders命名空间内.

    1
    2
    3
    function<bool(int)> f = bind(greater<int>(),placeholders::_1,2);
    cout<<f(4)<<endl; // 1
    cout<<f(1)<<endl; // 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<iostream>
#include <functional>

using namespace std;
class Test
{
public:
int sum(int a,int b) {return a + b;}
};
int sum(int a,int b){return a + b;}
void show(const string &str){cout<<str<<endl;}
int main()
{
// bind()返回函数对象
cout<<bind(sum,10,20)()<<endl;
cout<<bind(&Test::sum,Test(),10,90)()<<endl;

// 参数占位符
cout<<bind(sum,placeholders::_1,placeholders::_2)(1,2)<<endl;

// 如何保留下bind返回的函数对象?(如果不能保留下来,那么就只能一条语句用一次bind,很无语就)
function<void(void)> f = bind(show,"123456");
f();
}

bind 和 function 实现简易线程池

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include<thread>
#include<functional>
#include<vector>

using namespace std;

// Thread 封装了线程函数,并承担了生成新线程的任务(要将函数装入线程来启动)
class Thread{
public:
using FUNC = function<void(int)>; // 命名 function返回的函数对象类型为 void(int)
Thread(FUNC func,int id):_func(func),_id(id){}; // 传入线程函数 注意线程函数必须是个C线程函数。也即不
thread start() // 返回启动的线程
{
thread t(_func,_id); // 启动线程
return t;
}
private:
FUNC _func;
int _id;
};


class ThreadPool{
public:

ThreadPool(){}
~ThreadPool()
{
for(Thread *t:_pool)
{
delete t;
}
}

void startPool(int sz)
{
for(int i=0;i<sz;++i)
{ // bind返回函数对象 bind (函数地址,函数列表参数1 this,函数列表参数2 未知参数、用placeholder占位);
// (类成员函数在编译时,会生成this指针在参数列表首位)
_pool.push_back(new Thread(bind(&ThreadPool::runInThread,this,placeholders::_1),i));
}

for(int i=0;i<sz;++i)
{
_handler.push_back(_pool[i]->start()); // start 返回启动的线程
}

for(int i=0;i<sz;++i)
{
_handler[i].join();
}
}
private:
void runInThread(int i)
{
cout<<"runInthread id = "<<i<<endl;
return ;
}
private:
vector<Thread*> _pool; // 容器内的指针所指向的内存 需要我们手动释放
vector<thread> _handler; // 存放所有启动的线程
};

int main()
{
ThreadPool tp;
tp.startPool(10);
}

runInthread id = runInthread id = 3
runInthread id = 6
runInthread id = 5
0
runInthread id = 8
runInthread id = 4
runInthread id = 7
runInthread id = 2
runInthread id = 9
runInthread id = 1

lambda表达式(很强大)

  • 生成函数对象的新方式
  • [捕获外部变量](形参列表)->返回值{操作代码}
  • 如果返回值=void,那么”->void”可以省略
  • [捕获外部变量]
    • []:表示不捕获任何外部变量
    • [=]:以传值的方式捕获外部的所有变量
    • [&]:以传引用的方式捕获外部的所有变量
    • [this]:捕获外部this指针
    • [=,&a]:以传值的方式捕获外部的所有变量,但以传引用的方式捕获a变量
    • [a,b]:以值传递的方式捕获外部变量a和b
    • [a,&b]:a以传值的方式捕获,b以传引用的方式捕获
      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
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      //
      // Created by dell on 2022/3/20.
      //

      /*
      * 函数对象升级 -> lambda表达式
      * 函数对象缺点:
      * 使用在泛型算法参数传递,比较/自定义操作,优先级队列,智能指针删除器
      * lambda语法:
      * [捕获外部变量](形参列表)->返回值{操作代码}
      *
      * 如果返回值=void,那么"->void"可以省略
      * [捕获外部变量]
      * []:表示不捕获任何外部变量
      * [=]:以传值的方式捕获外部的所有变量
      * [&]:以传引用的方式捕获外部的所有变量
      * [this]:捕获外部this指针
      * [=,&a]:以传值的方式捕获外部的所有变量,但以传引用的方式捕获a变量
      * [a,b]:以值传递的方式捕获外部变量a和b
      * [a,&b]:a以传值的方式捕获,b以传引用的方式捕获
      */


      #include<iostream>
      #include<vector>
      #include<algorithm>

      using namespace std;

      template<typename T = int>
      class TestLambda
      {
      public:
      TestLambda(){}
      T operator()(T a,T b) const
      {
      return a + b;
      }
      };

      int main()
      {
      vector<int> vec;
      for(int i=0;i<10;++i)
      {
      vec.push_back(rand()%100);
      }

      // lambda生成函数对象传入泛型算法!这样就不用再去记忆greater,less。也不用bind绑定器绑定greater/less生成函数对象
      sort(vec.begin(),vec.end(),
      [](int a,int b)->bool{
      return a>b;
      });

      for_each(vec.begin(),vec.end(),[](int a)->void{cout<<a<<" ";});
      cout<<endl;


      // 问题解决了:应该怎么判断传入什么lambda参数()?
      // 就和给find_if传递普通的函数对象一样,函数对象所需要的参数 应当就是*迭代器
      // 因为find_if 中遍历会用到 FUNC(*迭代器) FUNC就是我门传入的函数对象
      // 这里lambda的(参数) 应当和find_if要求传入的函数对象的参数相同
      // 这个参数find_if语法上没法限制
      // 不过我们应该传入的参数是 find_if遍历时 遍历到的 " *迭代器 "
      vector<int>::iterator iter = find_if(vec.begin(),vec.end(),
      [](int a)->bool{return a<70;});
      vec.insert(iter,70);
      for_each(vec.begin(),vec.end(),[](int a)->void{cout<<a<<" ";});
      cout<<endl;
      return 0;
      }


      #if 0
      int main()
      {
      //
      TestLambda<> t;
      cout<<t(1,2)<<endl;

      // lambda表达式生成函数对象,替代我们写的模板函数对象类(冗余代码)
      auto t2 = [](int a,int b)->int{return a + b;};
      cout<<t2(1,2)<<endl;

      int x = 4,y = 5;
      auto t3 = [x,y] () mutable {
      int t = x;
      x = y;
      y = t;
      // 如果没加mutable的话
      // Cannot assign to a variable captured by copy in a non-mutable lambda
      // 不能在非可变lambda里修改按值捕获的变量
      };
      t3();
      cout<<x<<" "<<y<<endl;

      auto t4 = [&x,&y] () {
      int t = x;
      x = y;
      y = t;
      };
      t4();
      cout<<x<<" "<<y<<endl;
      }
      #endif

function配合lambda使用

  • 应该用什么类型来接收lamdba表达式返回的函数对象?/ 如何跨语句使用lambda表达式
    • 当然是function
  • 例子
    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
    64
    65
    66
    67
    68
    69
    70
    71
    72
    1、函数表
    unordered_map<int,function<int(int,int)>> f;
    f[0] = [](int a ,int b)->int{return a+b;};
    cout<<f[0](1,2)<<endl;

    2、删除器
    // 智能指针自定义删除器
    unique_ptr<FILE*,function<void(FILE*)>> up1(
    (fopen("a.txt", "w")),
    [](FILE* pf)->void{ fclose(pf);}
    );

    3. 容器比较规则
    // 灵活设定规则。并且可以对同一种对象进行不同规则比较
    class Data
    {
    public:
    Data(int a):m_a(a){}
    // bool operator< (const Data& rd) const // 如果自定义的话,必须是const函数。因为容器默认调用的比较函数对象的参数列表会用常量引用。而常量引用对象只能调用常量函数
    // {
    // return m_a<rd.m_a;
    // }
    int getData() const
    {
    return m_a;
    }
    private:
    int m_a;
    };

    int main()
    {
    // 采用function 配合 lambda表达式
    // 更加灵活的定义比较规则。不用在类内内置<号或者>号。
    using FUNC = function<bool(const Data& rd1,const Data& rd2)>;
    priority_queue<Data,vector<Data>,FUNC> q(
    [](const Data& rd1,const Data& rd2)->bool{
    return rd1.getData() < rd2.getData();
    });
    q.push(Data(10));
    q.push(Data(20));
    }


    template<typename _Tp, typename _Sequence = vector<_Tp>,
    typename _Compare = less<typename _Sequence::value_type> >
    class priority_queue{
    ...

    typedef typename _Sequence::value_type value_type;
    priority_queue()
    : c(), comp() { }
    explicit
    priority_queue(const _Compare& __x, _Sequence&& __s = _Sequence())
    : c(std::move(__s)), comp(__x)
    { std::make_heap(c.begin(), c.end(), comp); }

    protected:
    // See queue::c for notes on these names.
    _Sequence c;
    _Compare comp; // _comp为函数对象 _Compare为函数对象类
    }

    // less源码:所以自定义<必须为const函数
    template<typename _Tp>
    struct less : public binary_function<_Tp, _Tp, bool>
    {
    _GLIBCXX14_CONSTEXPR
    bool
    operator()(const _Tp& __x, const _Tp& __y) const
    { return __x < __y; }
    };

reinterpret_cast

ref

C++11 std::ref使用场景

重新搭建的小窝

  • Dell的硬盘坏掉了,来来回回修了快一个月
  • 什么环境都没得了,幸好笔记还都在
  • 虽然怕麻烦,不过重建一个自己的新窝还是很开心的。
  • 继续记录吧。