武陟县住房和城乡建设局网站,北京企业网站建设费用,重庆大渝网,怎么建设一个公司网站文章目录一、可变参数模板1.1 可变参数的函数模板1.2 递归函数方式展开参数包1.3 逗号表达式展开参数包1.4 empalce相关接口函数二、包装器function2.1 function用法2.2 例题#xff1a;逆波兰表达式求值2.3 验证三、绑定函数bind3.1 调整参数顺序3.2 固定绑定参数一、可变参数…
文章目录一、可变参数模板1.1 可变参数的函数模板1.2 递归函数方式展开参数包1.3 逗号表达式展开参数包1.4 empalce相关接口函数二、包装器function2.1 function用法2.2 例题逆波兰表达式求值2.3 验证三、绑定函数bind3.1 调整参数顺序3.2 固定绑定参数一、可变参数模板
在C语言中其实也有可变参数
1.1 可变参数的函数模板
C库里面也有很多使用可变参数函数模板的
template class ...Args
void fun(Args... args)
{}Args是一个模板参数包args是一个函数形参参数包 声明一个参数包Args…args这个参数包中可以包含0到任意个模板参数 以前只能传递一个对象做参数有了可变参数包就可以传递0~n个参数
template class ...Args
void fun(Args... args)
{// 获取参数包中有几个参数cout sizeof...(args) endl;
}int main()
{fun();fun(1);fun(1, 1.1);fun(1, 1.1, std::string(abc));std::vectorint v;fun(1, 1.1, std::string(abc), v);return 0;
}那么怎么把这些参数取出来呢
1.2 递归函数方式展开参数包
void fun()
{cout endl;
}template class T, class ...Args
void fun(T val, Args... args)
{cout val ;fun(args...);
}int main()
{fun();fun(1);fun(1, 1.1);fun(1, 1.1, std::string(abc));return 0;
}解释 按照箭头的方式调用最后当没有参数的时候就会走最上面的函数
1.3 逗号表达式展开参数包
template class T
void printArg(T val)
{cout val ;
}template class ...Args
void fun(Args... args)
{int arr[] { (printArg(args), 0)... };cout endl;
}int main()
{fun(1, 1.1, std::string(abc));return 0;
}这种展开参数包的方式不需要通过递归终止函数printArg不是一个递归终止函数只是一个处理参数包中每一个参数的函数。 (printArg(args), 0)先执行printArg(args)再得到逗号表达式的结果0。通过初始化列表来初始化一个变长数组, {(printArg(args), 0)...}将会展开成((printArg(arg1),0),(printArg(arg2),0), (printArg(arg3),0), etc... )最终会创建一个元素值都为0的数组。在创建数组的过程中会先执行逗号表达式前面的部分printArg(args)打印出参数也就是说在构造int数组的过程中就将参数包展开了这个数组的目的纯粹是为了在数组构造的过程展开参数包。
1.4 empalce相关接口函数
比较 insert emplace emplace的使用
int main()
{std::listint lt;lt.emplace_back();lt.emplace_back(1);lt.emplace_back(2);for (auto e : lt){cout e ;}cout \n;return 0;
}而emplace在插入自定义类型数据的时候会有区别
struct A
{A(int a 1, double b 2): _a(a), _b(b){}int _a;double _b;
};int main()
{std::listA lt;lt.push_back({ 1, 1.0 });lt.emplace_back(2, 2.0);//lt.push_back(3, 3.0);// errorfor (auto e : lt){cout e._a endl;}cout \n;return 0;
}上面使用push_back是先构造再拷贝构造而使用emplace_back就可以直接构造使用参数包。
验证一下 引入之前写过的string类
namespace yyh
{class string{public:typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str _size;}string(const char* str ): _size(strlen(str)), _capacity(_size){_str new char[_capacity 1];// _capacity表示有效字符个数strcpy(_str, str);cout string(const char* str) -- 构造函数 endl;}void swap(string s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}// 拷贝构造string(const string s): _size(strlen(s._str)), _capacity(s._size){_str new char[_capacity 1];strcpy(_str, s._str);cout string(const string s) -- 深拷贝 endl;}// 移动构造string(string s){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(){delete[] _str;_str nullptr;}char operator[](size_t pos){assert(pos _size);return _str[pos];}void reserve(size_t n){if (n _capacity){char* tmp new char[n 1];strcpy(tmp, _str);delete[] _str;_str tmp;_capacity n;}}void push_back(char ch){if (_size _capacity){size_t newcapacity _capacity 0 ? 4 : _capacity * 2;reserve(newcapacity);}_str[_size] ch;_size;_str[_size] \0;}string operator(char ch){push_back(ch);return *this;}const char* c_str() const{return _str;}private:char* _str nullptr;size_t _size 0;size_t _capacity 0;};
}struct A
{A(int a 1, const char* str ): _a(a), _str(str){}int _a;yyh::string _str;
};push_back emplace_back 总结 如果是左值使用push_back或者emplace_back没什么区别。
对于右值emplace_back把构造和拷贝构造合二为一成构造函数。 但是如果没有移动拷贝效率差距会很大emplace_back还是直接构造但是push_back就会走深拷贝。
二、包装器function
其实包装器function就是一个类模板。先来看一段代码
template class F, class T
void func(F fun, T val)
{static int cnt 1;cout cnt: cnt endl;cout cnt: cnt endl;
}int f1(int x)
{return x * 2;
}struct f2
{int operator()(int x){return x * 2;}
};int main()
{// 函数名func(f1, 2);// 仿函数对象func(f2(), 2);// lambda表达式func([](int x)-int { return x * 2; }, 2);return 0;
}可以看到以三种不同的方式调用func函数func函数就会被实例化出三份。
包装器可以很好的解决上面的问题
2.1 function用法 如果参数是两个int的话就是 functionint(int, int) fun1
int f1(int x)
{return x * 2;
}struct f2
{int operator()(int x){return x * 2;}
};class f3
{
public:static int muli(int x){return x * 2;}double muld(double x){return x * 2;}
};int main()
{// 普通函数functionint(int) fun1(f1);cout fun1(2) endl;// 仿函数functionint(int) fun2;fun2 f2();cout fun2(2) endl;// lambda表达式functionint(int) fun3;fun3 [](int x)-int {return 2 * x; };cout fun3(2) endl;// 静态成员函数指针functionint(int) fun4 f3::muli;cout fun4(2) endl;// 非静态成员函数指针functionint(f3/*this指针*/, int) fun5 f3::muld;cout fun5(f3(), 2) endl;return 0;
}这里要注意类成员函数的调用方法 对于静态成员函数因为没有this指针所以正常调用后面也可以不加 对于非静态成员函数因为含有this指针而this指针不能显示传递所以要传递对象。必须加。 当然也可以不在()内部加上对象可以使用lambda表达式中的[]捕获
f3 ff;
functionint(int) fun6 [ff](int x)-double {return ff.muld(x); };2.2 例题逆波兰表达式求值
题目链接 具体做法就不多叙述这里主要展示怎么使用function函数
class Solution {
public:int evalRPN(vectorstring tokens) {stackint st;mapstring, functionint(int, int) hash {{, [](int x, int y)-int{return x y;}},{-, [](int x, int y)-int{return x - y;}},{*, [](int x, int y)-int{return x * y;}},{/, [](int x, int y)-int{return x / y;}},};for(auto e : tokens){if(hash.count(e) 0){st.push(stoi(e));}else{int right st.top();st.pop();int left st.top();st.pop();st.push(hash[e](left, right));}}return st.top();}
};2.3 验证
在2.1中我们看道以那种方式会实例化三个模板函数。 而我们可以用function来解决这个问题
template class F, class T
T func(F fun, T val)
{static int cnt 1;cout cnt: cnt endl;cout cnt: cnt endl;return fun(val);
}int f1(int x)
{return x * 2;
}struct f2
{int operator()(int x){return x * 2;}
};class f3
{
public:static int muli(int x){return x * 2;}double muld(double x){return x * 2;}
};int main()
{// 函数名func(functionint(int)(f1), 2);// 仿函数对象f2 ff;func(functionint(int)(ff), 2);// lambda表达式func(functionint(int)([](int x)-int {return x * 2; }), 2);return 0;
}可以看出只实例化出了一份函数。
三、绑定函数bind 3.1 调整参数顺序
int Plus(int a, int b)
{return a - b;
}int main()
{functionint(int, int) fun1 bind(Plus, placeholders::_1, placeholders::_2);cout fun1(1, 2) endl;functionint(int, int) fun2 bind(Plus, placeholders::_2, placeholders::_1);cout fun2(1, 2) endl;return 0;
}从这里就可以看出_1代表第一个参数_2代表第二个参对于fun2就相当于把传参的顺序改变了。
3.2 固定绑定参数
class fun
{
public:static int muli(int x){return x * 2;}double muld(double x){return x * 2;}
};int main()
{// 非静态成员函数指针functionint(fun/*this指针*/, int) fun1 fun::muld;cout fun1(fun(), 2) endl;return 0;
}上面说过了使用非静态成员函数的时候得传递对象进去。如果我们不想传递这个参数呢
class fun
{
public:static int muli(int x){return x * 2;}double muld(double x){return x * 2;}
};int main()
{// 非静态成员函数指针functionint(fun/*this指针*/, int) fun1 fun::muld;cout fun1(fun(), 2) endl;// 绑定参数functionint(int) fun2 bind(fun::muld, fun(), std::placeholders::_1);cout fun2(2) endl;return 0;
}