C++11简介
统一的列表初始化
{}初始化
struct Point{int _x ;int _y ;};int main (){int array1 [] = { 1 , 2 , 3 , 4 , 5 };int array2 [ 5 ] = { 0 };Point p = { 1 , 2 };return 0 ;}
struct Point{int _x ;int _y ;};int main (){int x1 = 1 ;int x2 { 2 };int array1 []{ 1 , 2 , 3 , 4 , 5 };int array2 [ 5 ]{ 0 };Point p { 1 , 2 };// C++11 中列表初始化也可以适用于 new 表达式中int* pa = new int [ 4 ]{ 0 };return 0 ;}
创建对象时也可以使用列表初始化方式调用构造函数初始化
class Date{public :Date ( int year , int month , int day ): _year ( year ), _month ( month ), _day ( day ){cout << "Date(int year, int month, int day)" << endl ;}private :int _year ;int _month ;int _day ;};int main (){Date d1 ( 2022 , 1 , 1 ); // old style// C++11 支持的列表初始化,这里会调用构造函数初始化Date d2 { 2022 , 1 , 2 };Date d3 = { 2022 , 1 , 3 };return 0 ;}
std::initializer_list
std::initializer_list的介绍文档:
initializer_list - C++参考 (cplusplus.com)
int main (){// the type of il is an initializer_listauto il = { 10 , 20 , 30 };cout << typeid ( il ). name () << endl ;return 0 ;}
声明
auto
int main (){int i = 10 ;auto p = & i ;auto pf = strcpy ;cout << typeid ( p ). name () << endl ;cout << typeid ( pf ). name () << endl ;map < string , string > dict = { { "sort" , " 排序 " }, { "insert" , " 插入 " } };//map<string, string>::iterator it = dict.begin();auto it = dict . begin ();return 0 ;}
decltype
int main()
{
list<int>::iterator it1;
// typeid推出时一个单纯的字符串
cout << typeid(it1).name() << endl;
// 不能用来定义对象
//typeid(it1).name() it2;
// 可以用来定义对象
decltype(it1) it2;
cout << typeid(it2).name() << endl;
auto it3 = it1;
cout << typeid(it3).name() << endl;
auto ret3 = func1();
B<decltype(ret3)> bb1;
map<string, string> dict2 = { {"sort", "排序"}, {"insert", "插入"} };
auto it4 = dict2.begin();
B<decltype(it4)> bb2;
B<std::map<std::string, std::string>::iterator> bb2;
// auto和decltype有些地方增加代码读起来难度
return 0;
}
nullptr
#ifndef NULL#ifdef __cplusplus#define NULL 0#else#define NULL ((void *)0)#endif#endif
STL中一些变化
右值引用和移动语义
左值引用和右值引用
// 左值是一个表达式,可以取地址的
// 左值和右值,能否取地址
// 左值:可以取地址的
// 右值:不可以取地址的int main (){// 以下的 p 、 b 、 c 、 *p 都是左值int* p = new int ( 0 );int b = 1 ;const int c = 2 ;// 以下几个是对上面左值的左值引用int* & rp = p ;int & rb = b ;const int & rc = c ;int & pvalue = * p ;return 0 ;}
int main (){double x = 1.1 , y = 2.2 ;// 以下几个都是常见的右值10 ;x + y ;fmin ( x , y );// 以下几个都是对右值的右值引用int && rr1 = 10 ;double && rr2 = x + y ;double && rr3 = fmin ( x , y );// 这里编译会报错: error C2106: “=”: 左操作数必须为左值10 = 1 ;x + y = 1 ;fmin ( x , y ) = 1 ;return 0 ;}
int main (){double x = 1.1 , y = 2.2 ;int && rr1 = 10 ;const double && rr2 = x + y ;rr1 = 20 ;rr2 = 5.5 ; // 报错return 0 ;}
左值引用与右值引用比较
int main (){// 左值引用只能引用左值,不能引用右值。int a = 10 ;int & ra1 = a ; // ra 为 a 的别名//int& ra2 = 10; // 编译失败,因为 10 是右值// const 左值引用既可引用左值,也可引用右值。const int & ra3 = 10 ;const int & ra4 = a ;return 0 ;}
int main (){// 右值引用只能右值,不能引用左值。int && r1 = 10 ;// error C2440: “ 初始化 ”: 无法从 “int” 转换为 “int &&”// message : 无法将左值绑定到右值引用int a = 10 ;int && r2 = a ;// 右值引用可以引用 move 以后的左值int && r3 = std::move ( a );return 0 ;}
右值引用使用场景和意义
对于内置类型,和浅拷贝自定义类型,没有移动系列函数。
namespace xx
{
class string
{
public:
//...
// 拷贝构造
string(const string& s)
:_str(nullptr)
{
cout << "string(const string& s) -- 深拷贝" << endl;
string tmp(s._str);
swap(tmp);
}
// 移动构造
string(string&& s)
:_str(nullptr)
, _size(0)
, _capacity(0)
{
cout << "string(string&& s) -- 移动语义" << endl;
swap(s);
}
// 赋值重载
string& operator=(const string& s)
{
cout << "string& operator=(string s) -- 深拷贝" << endl;
string tmp(s);
swap(tmp);
return *this;
}
// 移动赋值
string& operator=(string&& s)
{
cout << "string& operator=(string&& s) -- 移动语义" << endl;
swap(s);
return *this;
}
//string operator+=(char ch)
string& operator+=(char ch)
{
push_back(ch);
return *this;
}
const char* c_str() const
{
return _str;
}
private:
char* _str;
size_t _size;
size_t _capacity; // 不包含最后做标识的\0
};
}
void func1 ( bit::string s ){}void func2 ( const bit::string & s ){}int main (){bit::string s1 ( "hello world" );// func1 和 func2 的调用我们可以看到左值引用做参数减少了拷贝,提高效率的使用场景和价值func1 ( s1 );func2 ( s1 );// string operator+=(char ch) 传值返回存在深拷贝// string& operator+=(char ch) 传左值引用没有拷贝提高了效率s1 += '!' ;return 0 ;}
namespace xx
{
bit::string to_string(int value)
{
bool flag = true;
if (value < 0)
{
flag = false;
value = 0 - value;
}
bit::string str;
while (value > 0)
{
int x = value % 10;
value /= 10;
str += ('0' + x);
}
if (flag == false)
{
str += '-';
}
std::reverse(str.begin(), str.end());
return str;
}
}
int main()
{
// 在bit::string to_string(int value)函数中可以看到,这里
// 只能使用传值返回,传值返回会导致至少1次拷贝构造(如果是一些旧一点的编译器可能是两次拷
贝构造)。
bit::string ret1 = bit::to_string(1234);
bit::string ret2 = bit::to_string(-1234);
return 0;
}
// 移动构造string ( string && s ): _str ( nullptr ), _size ( 0 ), _capacity ( 0 ){cout << "string(string&& s) -- 移动语义 " << endl ;swap ( s );}int main (){bit::string ret2 = bit::to_string (- 1234 );return 0 ;}
// 移动赋值string & operator = ( string && s ){cout << "string& operator=(string&& s) -- 移动语义 " << endl ;swap ( s );return * this ;}int main (){bit::string ret1 ;ret1 = bit::to_string ( 1234 );return 0 ;}// 运行结果:// string(string&& s) -- 移动语义// string& operator=(string&& s) -- 移动语义
右值引用引用左值及其一些更深入的使用场景分析
template < class _Ty >inline typename remove_reference < _Ty > :: type && move ( _Ty && _Arg ) _NOEXCEPT{// forward _Arg as movablereturn (( typename remove_reference < _Ty > :: type && ) _Arg );}
int main (){bit::string s1 ( "hello world" );// 这里 s1 是左值,调用的是拷贝构造bit::string s2 ( s1 );// 这里我们把 s1 move 处理以后 , 会被当成右值,调用移动构造// 但是这里要注意,一般是不要这样用的,因为我们会发现 s1 的// 资源被转移给了 s3 , s1 被置空了。bit::string s3 ( std::move ( s1 ));return 0 ;}
STL容器插入接口函数也增加了右值引用版本:
list::p ush_back - C++参考 (cplusplus.com)
vector::p ush_back - C++参考 (cplusplus.com)
void push_back ( value_type && val );int main (){list < bit::string > lt ;bit::string s1 ( "1111" );// 这里调用的是拷贝构造lt . push_back ( s1 );// 下面调用都是移动构造lt . push_back ( "2222" );lt . push_back ( std::move ( s1 ));return 0 ;}运行结果:// string(const string& s) -- 深拷贝// string(string&& s) -- 移动语义// string(string&& s) -- 移动语义
完美转发
// 函数模版里面,这里可以叫万能引用
// 实参传左值,就推成左值引用
// 实参传右值,就推成右值引用
void Fun ( int & x ){ cout << " 左值引用 " << endl ; }void Fun ( const int & x ){ cout << "const 左值引用 " << endl ; }void Fun ( int && x ){ cout << " 右值引用 " << endl ; }void Fun ( const int && x ){ cout << "const 右值引用 " << endl ; }// 模板中的 && 不代表右值引用,而是万能引用,其既能接收左值又能接收右值。// 模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力,// 但是引用类型的唯一作用就是限制了接收的类型,后续使用中都退化成了左值,// 我们希望能够在传递过程中保持它的左值或者右值的属性 , 就需要用我们下面学习的完美转发template < typename T >void PerfectForward ( T && t ){Fun ( t );}int main (){PerfectForward ( 10 ); // 右值int a ;PerfectForward ( a ); // 左值PerfectForward ( std::move ( a )); // 右值const int b = 8 ;PerfectForward ( b ); // const 左值PerfectForward ( std::move ( b )); // const 右值return 0 ;}
解决方法:
std::forward 完美转发在传参的过程中保留对象原生类型属性
void Fun ( int & x ){ cout << " 左值引用 " << endl ; }void Fun ( const int & x ){ cout << "const 左值引用 " << endl ; }void Fun ( int && x ){ cout << " 右值引用 " << endl ; }void Fun ( const int && x ){ cout << "const 右值引用 " << endl ; }// std::forward<T>(t) 在传参的过程中保持了 t 的原生类型属性。template < typename T >void PerfectForward ( T && t ){Fun ( std::forward < T > ( t ));}int main (){PerfectForward ( 10 ); // 右值int a ;PerfectForward ( a ); // 左值PerfectForward ( std::move ( a )); // 右值const int b = 8 ;PerfectForward ( b ); // const 左值PerfectForward ( std::move ( b )); // const 右值return 0 ;}
完美转发实际中的使用场景:
template<class T>
struct ListNode
{
ListNode* _next = nullptr;
ListNode* _prev = nullptr;
T _data;
};
template<class T>
class List
{
typedef ListNode<T> Node;
public:
List()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
}
void PushBack(T&& x)
{
//Insert(_head, x);
Insert(_head, std::forward<T>(x));
}
void PushFront(T&& x)
{
//Insert(_head->_next, x);
Insert(_head->_next, std::forward<T>(x));
}
void Insert(Node* pos, T&& x)
{
Node* prev = pos->_prev;
Node* newnode = new Node;
newnode->_data = std::forward<T>(x); // 关键位置
// prev newnode pos
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = pos;
pos->_prev = newnode;
}
void Insert(Node* pos, const T& x)
{
Node* prev = pos->_prev;
Node* newnode = new Node;
newnode->_data = x; // 关键位置
// prev newnode pos
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = pos;
pos->_prev = newnode;
}
private:
Node* _head;
};
int main()
{
List<bit::string> lt;
lt.PushBack("1111");
lt.PushFront("2222");
return 0;
}
确保参数层层传递的过程中保持右值属性!!!不然传一层就成左值了
新的类功能
// 以下代码在 vs2013 中不能体现,在 vs2019 下才能演示体现上面的特性。class Person{public :Person ( const char* name = "" , int age = 0 ): _name ( name ), _age ( age ){}/*Person(const Person& p):_name(p._name),_age(p._age){}*//*Person& operator=(const Person& p){if(this != &p){_name = p._name;_age = p._age;}return *this;}*//*~Person(){}*/private :xx::string _name ;int _age ;};int main (){Person s1 ;Person s2 = s1 ;Person s3 = std::move ( s1 );Person s4 ;s4 = std::move ( s2 );return 0 ;}
class Person{public :Person ( const char* name = "" , int age = 0 ): _name ( name ), _age ( age ){}Person ( const Person & p ): _name ( p . _name ), _age ( p . _age ){}Person ( Person && p ) = default ;private :xx::string _name ;int _age ;};int main (){Person s1 ;Person s2 = s1 ;Person s3 = std::move ( s1 );return 0 ;}
class Person{public :Person ( const char* name = "" , int age = 0 ): _name ( name ), _age ( age ){}Person ( const Person & p ) = delete ;private :xx::string _name ;int _age ;};int main (){Person s1 ;Person s2 = s1 ;Person s3 = std::move ( s1 );return 0 ;}
lambda表达式
#include <algorithm>#include <functional>int main (){int array [] = { 4 , 1 , 8 , 5 , 3 , 7 , 0 , 9 , 2 , 6 };// 默认按照小于比较,排出来结果是升序std::sort ( array , array + sizeof ( array ) / sizeof ( array [ 0 ]));// 如果需要降序,需要改变元素的比较规则std::sort ( array , array + sizeof ( array ) / sizeof ( array [ 0 ]), greater < int > ());return 0 ;}
如果待排序元素为自定义类型,需要用户定义排序时的比较规则:
struct Goods{string _name ; // 名字double _price ; // 价格int _evaluate ; // 评价Goods ( const char* str , double price , int evaluate ): _name ( str ), _price ( price ), _evaluate ( evaluate ){}};struct ComparePriceLess{bool operator ()( const Goods & gl , const Goods & gr ){return gl . _price < gr . _price ;}};struct ComparePriceGreater{bool operator ()( const Goods & gl , const Goods & gr ){return gl . _price > gr . _price ;}};int main (){vector < Goods > v = { { " 苹果 " , 2.1 , 5 }, { " 香蕉 " , 3 , 4 }, { " 橙子 " , 2.2 ,3 }, { " 菠萝 " , 1.5 , 4 } };sort ( v . begin (), v . end (), ComparePriceLess ());sort ( v . begin (), v . end (), ComparePriceGreater ());}
lambda表达式例子
例1:
int main()
{
vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,
3 }, { "菠萝", 1.5, 4 } };
//方法一:
auto priceLess = [](const Goods& g1, const Goods& g2)
{
return g1._price < g2._price;
};
sort(v.begin(), v.end(), priceLess);
//cout << typeid(priceLess).name() << endl;
//方法二:
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2)
{
return g1._price > g2._price;
});
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2)
{
return g1._evaluate < g2._evaluate;
});
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2)
{
return g1._evaluate > g2._evaluate;
});
return 0;
}
int main()
{
// lambda
auto add1 = [](int a, int b)->int {return a + b; };
// 返回值可以省略
auto add2 = [](int a, int b) {return a + b; };
// 没有参数,参数列表可以省略
auto func1 = [] {cout << "hello world" << endl; };
cout << typeid(add1).name() << endl;
cout << typeid(add2).name() << endl;
cout << typeid(func1).name() << endl;
cout << add1(1, 2) << endl;
func1();
return 0;
}
lambda表达式语法
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
int main()
{
// 最简单的lambda表达式, 该lambda表达式没有任何意义
[] {};
// 省略参数列表和返回值类型,返回值类型由编译器推导为int
int a = 3, b = 4;
[=] {return a + 3; };
// 省略了返回值类型,无返回值类型
auto fun1 = [&](int c) {b = a + c; };
fun1(10);
cout << a << " " << b << endl;
// 各部分都很完善的lambda函数
auto fun2 = [=, &b](int c)->int {return b += a + c; };
cout << fun2(10) << endl;
// 复制捕捉x
int x = 10;
auto add_x = [x](int a) mutable { x *= 2; return a + x; };
cout << add_x(10) << endl;
return 0;
}
void ( * PF )();int main (){auto f1 = []{ cout << "hello world" << endl ; };auto f2 = []{ cout << "hello world" << endl ; };// 此处先不解释原因,等 lambda 表达式底层实现原理看完后,大家就清楚了//f1 = f2; // 编译失败 ---> 提示找不到 operator=()// 允许使用一个 lambda 表达式拷贝构造一个新的副本auto f3 ( f2 );f3 ();// 可以将 lambda 表达式赋值给相同类型的函数指针PF = f2 ;PF ();return 0 ;}
函数对象与lambda表达式
class Rate
{
public:
Rate(double rate) : _rate(rate)
{}
double operator()(double money, int year)
{
return money * _rate * year;
}
private:
double _rate;
};
int main()
{
// 函数对象
double rate = 0.49;
Rate r1(rate);
r1(10000, 2);
// lamber
auto r2 = [=](double monty, int year)->double {return monty * rate * year;};
r2(10000, 2);
return 0;
}
可变参数模板
// Args 是一个模板参数包, args 是一个函数形参参数包// 声明一个参数包 Args...args ,这个参数包中可以包含 0 到任意个模板参数。template < class ... Args >void ShowList ( Args ... args ){}
递归函数方式展开参数包
// 递归终止函数template < class T >void ShowList ( const T & t ){cout << t << endl ;}// 展开函数template < class T , class ... Args >void ShowList ( T value , Args ... args ){cout << value << " " ;ShowList ( args ...);}int main (){ShowList ( 1 );ShowList ( 1 , 'A' );ShowList ( 1 , 'A' , std::string ( "sort" ));return 0 ;}
逗号表达式展开参数包
template < class T >void PrintArg ( T t ){cout << t << " " ;}// 展开函数template < class ... Args >void ShowList ( Args ... args ){int arr [] = { ( PrintArg ( args ), 0 )... };cout << endl ;}int main (){ShowList ( 1 );ShowList ( 1 , 'A' );ShowList ( 1 , 'A' , std::string ( "sort" ));return 0 ;}
STL容器中的empalce相关接口函数:
vector::emplace_back - C++参考 (cplusplus.com)
list::emplace_back - C++参考 (cplusplus.com)
template < class ... Args >void emplace_back ( Args && ... args );
int main (){std::list < std::pair < int , char > > mylist ;// emplace_back 支持可变参数,拿到构建 pair 对象的参数后自己去创建对象// 那么在这里我们可以看到除了用法上,和 push_back 没什么太大的区别mylist . emplace_back ( 10 , 'a' );mylist . emplace_back ( 20 , 'b' );mylist . emplace_back ( make_pair ( 30 , 'c' ));mylist . push_back ( make_pair ( 40 , 'd' ));mylist . push_back ({ 50 , 'e' });for ( auto e : mylist )cout << e . first << ":" << e . second << endl ;return 0 ;}
例子二:
int main (){// 下面我们试一下带有拷贝构造和移动构造的 bit::string ,再试试呢// 我们会发现其实差别也不到, emplace_back 是直接构造了, push_back// 是先构造,再移动构造,其实也还好。std::list < std::pair < int , bit::string > > mylist ;mylist . emplace_back ( 10 , "sort" );mylist . emplace_back ( make_pair ( 20 , "sort" ));mylist . push_back ( make_pair ( 30 , "sort" ));mylist . push_back ({ 40 , "sort" });return 0 ;}
例子三:
int main()
{
bit::list<pair<bit::string, int>> lt;
cout << endl;
pair<bit::string, int> kv1("xxxxx", 1);
lt.push_back(kv1);
lt.push_back(move(kv1));
cout << endl;
// 直接传pair的对象效果跟push_back系列是一样的
pair<bit::string, int> kv2("xxxxx", 1);
lt.emplace_back(kv2);
lt.emplace_back(move(kv2));
cout << endl;
// 直接传构造pair的参数包,参数包一直往下传,底层直接构造
lt.emplace_back("xxxxx", 1);
return 0;
}
底层实现->实例化成具体函数:
主要区别:emplace接口直接传构造对象的参数包才体现出与insert接口不同的效果
insert系列接口通常接受值或者一个由值构造的对象作为参数,然后将其插入到容器中。而emplace系列接口则接受的是构造容器内元素所需的参数,并直接在容器内构造对象,而不需要进行拷贝或移动操作。
因此,emplace系列接口相对于insert系列接口具有以下优势:
1.减少了不必要的拷贝或移动操作:通过直接在容器内构造对象,emplace系列接口避免了将参数进行拷贝或移动到容器内的过程,可以提高性能。
2.更灵活:emplace系列接口可以接受任意数量的参数,并根据参数列表直接在容器内构造对象,因此更加灵活,能够处理更多种类的构造方式。
总的来说,相对于insert系列接口,emplace系列接口在性能上有一定的优势,并且能够提供更灵活的构造方式,特别是在处理大量元素或者需要支持移动语义的情况下,emplace系列接口会更加高效。
总结:
包装器
function包装器
function - C++ Reference (cplusplus.com)
//ret = func(x);
// 上面func可能是什么呢?那么func可能是函数名?函数指针?函数对象(仿函数对象)?也有可能
//是lamber表达式对象?所以这些都是可调用的类型!如此丰富的类型,可能会导致模板的效率低下!
//为什么呢?我们继续往下看
template<class F, class T>
T useF(F f, T x)
{
static int count = 0;
cout << "count:" << ++count << endl;
cout << "count:" << &count << endl;
return f(x);
}
double f(double i)
{
return i / 2;
}
struct Functor
{
double operator()(double d)
{
return d / 3;
}
};
int main()
{// 函数名
cout << useF(f, 11.11) << endl;
// 函数对象
cout << useF(Functor(), 11.11) << endl;
// lamber表达式
cout << useF([](double d)->double { return d / 4; }, 11.11) << endl;
return 0;
}
//结果:三次count的地址都不同,即函数模板实例化了三份
std::function 在头文件 < functional >// 类模板原型如下template < class T > function ; // undefinedtemplate < class Ret , class ... Args >class function < Ret ( Args ...) > ;模板参数说明:Ret : 被调用函数的返回类型Args… :被调用函数的形参
// 使用方法如下:
#include <functional>
int f(int a, int b)
{
return a + b;
}
struct Functor
{
public:
int operator() (int a, int b)
{
return a + b;
}
};
class Plus
{
public:
static int plusi(int a, int b) //静态成员函数没有this指针
{
return a + b;
}
double plusd(double a, double b) //this 指针是 “ 成员函数 ” 第一个隐含的指针形参
{
return a + b;
}
};
int main()
{
// 函数名(函数指针)
std::function<int(int, int)> func1 = f;
cout << func1(1, 2) << endl;
// 函数对象
std::function<int(int, int)> func2 = Functor();
cout << func2(1, 2) << endl;
// lamber表达式
std::function<int(int, int)> func3 = [](const int a, const int b)
{return a + b; };
cout << func3(1, 2) << endl;
// 类的成员函数
// 成员函数的函数指针 规定写法(一定加上&):&类型::函数名
std::function<int(int, int)> func4 = &Plus::plusi;
cout << func4(1, 2) << endl;
//这里参数Plus(或Plus*)不是传递this指针参数,因为this指针不能显示传递,而是传递对象(记住即可)
//写法一:
std::function<double(Plus, double, double)> func5 = &Plus::plusd;
cout << func5(Plus(), 1.1, 2.2) << endl;
//写法二:
std::function<double(Plus*, double, double)> func6 = &Plus::plusd;
Plus plus;
cout << func6(&plus, 1.1, 2.2) << endl;
return 0;
}
有了包装器,如何解决模板的效率低下,实例化多份的问题呢?
#include <functional>
template<class F, class T>
T useF(F f, T x)
{
static int count = 0;
cout << "count:" << ++count << endl;
cout << "count:" << &count << endl;
return f(x);
}
double f(double i)
{
return i / 2;
}
struct Functor
{
double operator()(double d)
{
return d / 3;
}
};
int main()
{
// 函数名
std::function<double(double)> func1 = f;
cout << useF(func1, 11.11) << endl;
// 函数对象
std::function<double(double)> func2 = Functor();
cout << useF(func2, 11.11) << endl;
// lamber表达式
std::function<double(double)> func3 = [](double d)->double { return d /
4; };
cout << useF(func3, 11.11) << endl;
return 0;
}
包装器只实例化了一份 ,效率提升!!!
// 使用包装器以后的玩法
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
//命令->动作(函数)
map<string,function<int(int,int)>> opfucMap{
{"+",[](int a,int b){return a+b;}},
{"-",[](int a,int b){return a-b;}},
{"*",[](int a,int b){return a*b;}},
{"/",[](int a,int b){return a/b;}}
};
for(auto& str:tokens)
{
if(opfucMap.count(str)) // 操作符 (为1即为操作符,操作符运算,运算后的结果再入栈)
{
int right=st.top();
st.pop();
int left=st.top();
st.pop();
st.push(opfucMap[str](left,right));
}
else // 操作数 (为0即为操作数,操作数入栈)
{
st.push(stoi(str));
}
}
return st.top();
}
};
bind(绑定)
绑定 - C++ 参考 (cplusplus.com)
std::bind函数定义在头文件中,是一个函数模板,它就像一个函数包装器(适配器),
接受一个可 调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。一般而 言,我们用它可以把一个原本接收N个参数的函数fn,通过绑定一些参数,返回一个接收M个(M 可以大于N,但这么做没什么意义)参数的新函数。同时,使用std::bind函数还可以实现参数顺 序调整等操作。
// 原型如下:template < class Fn , class ... Args >/* unspecified */ bind ( Fn && fn , Args && ... args );// with return type (2)template < class Ret , class Fn , class ... Args >/* unspecified */ bind ( Fn && fn , Args && ... args );模板参数说明:Ret : 被调用函数的返回类型(一般不关心,很少使用)用法:Args… :被调用函数的形参Fn: 接受一个可 调用对象
Ret场景简单用法:
#include<iostream>
using namespace std;
#include <functional>
int Sub(int a, int b)
{
return a - b;
}
int main()
{
//调整顺序
auto f2 = bind(Sub, placeholders::_1, placeholders::_2);
cout << f2(10, 5) << endl;
auto f1 = bind(Sub, placeholders::_2, placeholders::_1);
cout << f1(10, 5) << endl;
return 0;
}
#include<iostream>
using namespace std;
#include <functional>
class Sub
{
public:
Sub(int x)
:_x(x)
{}
int sub(int a, int b)
{
return (a - b) * _x;
}
private:
int _x;
};
int main()
{ // 绑定,调整参数个数
auto f4 = bind(&Sub::sub, Sub(1), placeholders::_1, placeholders::_2);
cout << f4(10, 5) << endl;
这么写也行
//auto f4 = bind(&Sub::sub, &Sub(1), placeholders::_1, placeholders::_2);
//cout << f4(10, 5) << endl;
auto f5 = bind(&Sub::sub, &Sub(2), placeholders::_1, placeholders::_2);
cout << f5(10, 5) << endl;
return 0;
}
例子3:调整参数个数(参数位置任意绑定)
#include<iostream>
using namespace std;
#include <functional>
void fx(const string& name, int x, int y)
{
cout << name << "->[" << "血量:" << x << ",蓝:" << y << ']' << endl;
}
int main()
{
以前写法,第一个参数一样的每次都要写,麻烦
//fx("王昭君", 80, 20);
//fx("王昭君", 85, 10);
//fx("王昭君", 99, 0);
//fx("王昭君", 99, 80);
//
//fx("亚瑟", 99, 80);
//fx("亚瑟", 91, 80);
//fx("亚瑟", 5, 80);
//使用bind后的写法
//
//绑定第一个参数
auto f6 = bind(fx, "王昭君", placeholders::_1, placeholders::_2);
f6(80, 20);
f6(85, 10);
f6(99, 0);
f6(99, 80);
auto f7 = bind(fx, "亚瑟", placeholders::_1, placeholders::_2);
f7(80, 20);
f7(85, 10);
f7(99, 0);
f7(99, 80);
//绑定中间参数
function<void(std::string, int)> f8 = bind(fx, placeholders::_1, 80, placeholders::_2);
f8("武则天", 50);
f8("韩信", 40);
return 0;
}
// 使用举例
#include <functional>
int Plus(int a, int b)
{
return a + b;
}
class Sub
{
public:
int sub(int a, int b)
{
return a - b;
}
};
int main()
{
//表示绑定函数plus 参数分别由调用 func1 的第一,二个参数指定
std::function<int(int, int)> func1 = std::bind(Plus, placeholders::_1,placeholders::_2);
//auto func1 = std::bind(Plus, placeholders::_1, placeholders::_2);
//func2的类型为 function<int(int, int)> 与func1类型一样
//表示绑定函数 plus 的第一,二为: 1, 2
auto func2 = std::bind(Plus, 1, 2);
cout << func1(1, 2) << endl;
cout << func2() << endl;
Sub s;
// 绑定成员函数
std::function<int(int, int)> func3 = std::bind(&Sub::sub, s,placeholders::_1, placeholders::_2);
// 参数调换顺序
std::function<int(int, int)> func4 = std::bind(&Sub::sub, s,placeholders::_2, placeholders::_1);
cout << func3(1, 2) << endl;
cout << func4(1, 2) << endl;
return 0;
}