• 【C++重点语法下】可变参数模板,STL里面的push_back和emplace_back区别 ,包装器function,bind


    目录

    1.可变参数模板

            1.1取出参数包内的参数方法一:

            1.2取出参数包内的参数方法二:  

            1.3STL里面的push_back和emplace_back区别 

    2.包装器function

           2.1function(头文件functional)

            2.1.1可调用类型和包装器 

                    2.1.2类的成员函数和包装器 

            2.2bind


    1.可变参数模板

    参数args前面有省略号,所以它就是一个可变模版参数,我们把带省略号的参数称为“参数包”,它里面包含了0到N(N>=0)个模版参数。 

    1. //argument翻译:参数
    2. template <class ...Args>
    3. void ShowList(Args... arg)
    4. {
    5. cout << sizeof...(arg) << endl;
    6. cout << sizeof...(Args) << endl<< endl;
    7. }
    8. int main()
    9. {
    10. ShowList(1);
    11. ShowList(1, 'A');
    12. ShowList(1, 'A', std::string("sort"));
    13. return 0;
    14. }

    使用sizeof需要在(变量)之前加...,即可算出参数包内的个数 

    1.1取出参数包内的参数方法一:

    递归调用 

    1. template<class T,class ...Args>
    2. // 解析并打印参数包中每个参数的类型及值
    3. void ShowList(T val, Args...args)
    4. {
    5. cout << typeid(T).name() << " " << val << endl;
    6. ShowList(args...);
    7. }

    执行结果:参数包的元素在递归中会被拿完;但是至少应该有一个参数才可以继续递归(参数包的参数可以为0-n),但是T必须有参数实例化;而且没有递归调用结束条件; 

     

    1. // 递归终止函数
    2. template<class T>
    3. void ShowList(T val)
    4. {
    5. cout << typeid(T). name() << " " << val << endl << endl;
    6. }
    7. template<class T,class ...Args>
    8. 解析并打印参数包中每个参数的类型及值
    9. void ShowList(T val, Args...args)
    10. {
    11. cout << typeid(T).name() << " " << val << endl;
    12. ShowList(args...);
    13. }
    14. int main()
    15. {
    16. ShowList(1);
    17. ShowList(1, 'A');
    18. ShowList(1, 'A', std::string("sort"));
    19. return 0;
    20. }

    执行结果:

    1.2取出参数包内的参数方法二:  

        int arr[] = { PrintArg(args)... };很奇怪的语法,只有硬背 

    • { PrintArg(args)... };把这个展开;有几个参数就展开几个,比如参数包内有3个参数,int arr[]={PrintArg(args),PrintArg(args),PrintArg(args)};
    1. template <class T>
    2. int PrintArg(T val)
    3. {
    4. T copy(val);
    5. cout << typeid(T).name() << ":" << val << endl;
    6. }
    7. //展开函数
    8. template <class ...Args>
    9. void ShowList(Args... args)
    10. {
    11. int arr[] = { PrintArg(args)... };
    12. cout << endl;
    13. }
    14. int main()
    15. {
    16. ShowList(1);
    17. ShowList(1, 'A');
    18. ShowList(1, 'A', std::string("sort"));
    19. return 0;
    20. }

    执行结果:

    1.3STL里面的push_back和emplace_back区别 

    • push_back是左值和右值的引用;emplace_back是万能引用
    • emplace_back使用的是参数包
    • 右值:emplace_back是:直接使用参数构造;push_back是使用参数先构造临时对象,再资源转移
    • 左值:都是直接使用左值拷贝构造
    • emplace_back在右值比push_back效率高一点点;优化了但是只能优化一点点;

    2.包装器function

    ret = func(x);

    上面func可能是什么呢?那么func可能是函数名?函数指针?函数对象(仿函数对象)?也有可能是lamber表达式对象?

    • 例lambda表达是:auto fun=[](int a,int b)->int{return a+b;};
    1. template<class F, class T>
    2. void useF(F f, T x)
    3. {
    4. static int count = 0;
    5. cout << "count:" << ++count << endl;
    6. cout << "count:" << &count << endl;
    7. }
    8. //普通函数
    9. double f(double i)
    10. {
    11. return i / 2;
    12. }
    13. struct Functor
    14. {
    15. double operator()(double d)
    16. {
    17. return d / 3;
    18. }
    19. };
    20. int main()
    21. {
    22. // 函数名
    23. useF(f, 11.11);
    24. // 函数对象
    25. useF(Functor(), 11.11);
    26. // lamber表达式
    27. useF([](double d)->double { return d / 4; }, 11.11);
    28. return 0;
    29. }

    执行结果:static修饰的局部变量声明周期变长,如果实例化的是一份;应该是1,2,3;且地址不同说明不是一个;

    结论:将实例化出3份,效率低,有没有办法实例化一份就好

    先看下面,懂了再来看这几句代码

    1. std::function<double(double)> func1 = f;
    2. useF(func1, 11.11);
    3. // 函数对象
    4. std::function<double(double)> func2 = Functor();
    5. useF(func2, 11.11);
    6. // lamber表达式
    7. std::function<double(double)> func3 = [](double d)->double { return d /4; };
    8. useF(func3, 11.11);

     2.1function(头文件functional)

    2.1.1可调用类型和包装器 

    1. #include
    2. int f(int a, int b)
    3. {
    4. return a + b;
    5. }
    6. struct Functor
    7. {
    8. public:
    9. int operator() (int a, int b)
    10. {
    11. return a + b;
    12. }
    13. };
    14. int main()
    15. {
    16. // 函数名(函数指针)
    17. std::function<int(int, int)> func1 = f;
    18. cout << func1(1, 2) << endl;
    19. // 函数对象/仿函数
    20. std::function<int(int, int)> func2 = Functor();
    21. cout << func2(1, 2) << endl;
    22. // lamber表达式
    23. std::function<int(int, int)> func3 = [](const int a, const int b)
    24. {return a + b; };
    25. cout << func3(1, 2) << endl;
    26. return 0;
    27. }

    执行结果: 

    2.1.2类的成员函数和包装器 

     类的成员函数和包装器 

    1. class Plus
    2. {
    3. public:
    4. static int plusi(int a, int b)
    5. {
    6. return a + b;
    7. }
    8. double plusd(double a, double b)
    9. {
    10. return a + b;
    11. }
    12. };
    13. int main()
    14. {
    15. // 类的成员函数
    16. std::function<int(int, int)> func4 = &Plus::plusi;
    17. cout << func4(1, 2) << endl;
    18. std::function<double(Plus, double, double)> func5 = &Plus::plusd;
    19. cout << func5(Plus(), 1.1, 2.2) << endl;
    20. return 0;
    21. }

    1. std::function func4 = &Plus::plusi; 静态成员函数可以省略&取地址符号(推荐不省略以免搞混);因为静态成员函数可以使用:类名::静态成员函数使用
    2. std::function func5 = &Plus::plusd;普通成员函数不可以使用类名::静态成员函数名类使用;必须要有一个对象来访问,&取地址符号也不可以省略;所以多了一个参数;绑定可以解决多一个参数的问题

     2.2bind

    bind是一个函数模板,它就像一个函数包装器(适配器),接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表

    1. 通过bind调整参数顺序
    2. 通过bind调整参数个数

    通过bind调整参数顺序 

    1. int SubFunc(int x, int y)
    2. {
    3. return x - y;
    4. }
    5. int main()
    6. {
    7. function<int(int, int)> func1 = SubFunc;
    8. cout << func1(10, 5) << endl;
    9. //没有改变参数顺序
    10. function<int(int, int)> func2 = bind(SubFunc, placeholders::_1, placeholders::_2);
    11. cout << func2(10, 5) << endl;
    12. //交换参数顺序
    13. function<int(int, int)> func3 = bind(SubFunc, placeholders::_2, placeholders::_1);
    14. cout << func3(10, 5) << endl;
    15. return 0;
    16. }

      

     通过bind调整参数个数

    1. class Add
    2. {
    3. public:
    4. int add(int x, int y)
    5. {
    6. return x + y;
    7. }
    8. };
    9. int main()
    10. {
    11. //需要对象来调用普通函数
    12. function<int(Add, int, int)> func4 = &Add::add;
    13. cout << "func4:" << func4(Add(), 10, 20) << endl;
    14. //使用bind改变参数个数
    15. function<int(int, int)> func5 = bind(&Add::add,Add(), placeholders::_1, placeholders::_2);
    16. cout << "func5:" << func5(10, 20) << endl;
    17. return 0;
    18. }

    可以使用auto接受,但是function的参数很明确; 

  • 相关阅读:
    uploadifive上传工具php版使用
    ByteBuffer杂记
    EventListener
    c++ 之安装opencv显示图片
    web前端期末大作业:婚纱网页主题网站设计——唯一旅拍婚纱公司网站HTML+CSS+JavaScript
    web前端网页设计与制作:HTML+CSS旅游网页设计——桂林旅游(3页) web前端旅游风景网页设计与制作 div静态网页设计
    gbase 8a 基础语法概念问题
    【算法】spfa算法求最短路(没有负环)
    学习笔记——Java入门第一季
    JavaScript 68 JavaScript Browser BOM 68.7 JavaScript Timing 事件
  • 原文地址:https://blog.csdn.net/m0_72964546/article/details/128126568