【理论实践】指向类模板函数的指针的使用(以std::list为例)
来源:互联网 发布:漫画王软件 编辑:程序博客网 时间:2024/06/05 07:02
假设有这个一个场景,我们希望根据条件决定插入元素到list首或尾,条件判断一次,插入操作多次,例如二叉树,至少要处理左和右各一次。
普通的代码很简单,每次操作时,都判断一下,简化一下是一个三元表达式。
巧妙一点的,可以定义一个变量指定接口函数,根据条件设定指定的值,然后后面就可以直接用函数指针了,不再需要重复判断,实现代码如下:
list<int*> l; typedef void (list<int*>::*fun_t)(int* const &); bool back = true; fun_t f = back ? (fun_t)&list<int*>::push_back : (fun_t)&list<int*>::push_front; //处理条件 int* v = nullptr; v++; (l.*f)(nullptr); //多次使用 (l.*f)(v); //多次使用
几个难点如下,假设相关理论知识已经具备,不解释。
1、类成员函数指针的使用
2、函数重载处理
3、模板类型为指针时注意事项
4、左值类型和右值类型
下文一改以往的思路,带着大家从最容易出错的起点上,一步一步改正确。部分确实是自己命中的,部分是自己推测大部分人会命中的。
1、直观上的写法
list<int> l; auto f = &list<int>::push_back; //编译错误 int v = 1; (l.*f)(0); //注意不能写成 l.*f(1); (l.*f)(v); return 0;错误:error: unable to deduce ‘auto’ from ‘& std::list<_Tp, _Alloc>::push_back<int, std::allocator<int> >’
原因是push_back重载了,无法自动匹配类型,看一下push_back的定义如下
void push_back (const value_type& val); //适用于左值和右值
void push_back (value_type&& val); //仅适用于右值,移动
解决函数重载的办法是定义好对应参数的类型,使只唯一匹配重载的一个函数。
2、第二版代码
list<int> l; typedef void (list<int>::*fun_t)(const int&); //定义类型 fun_t f = &list<int>::push_back; int v = 1; (l.*f)(0); //注意不能写成 l.*f(1); (l.*f)(v);如果使用重载的另一个函数,则代码如下,
list<int> l; typedef void (list<int>::*fun_t)(int&&); fun_t f = &list<int>::push_back; int v = 1; (l.*f)(0); //注意不能写成 l.*f(1); (l.*f)(v); //编译报错, (l.*f)(move(v));正确报错:error: cannot bind ‘int’ lvalue to ‘int&&’
函数接受一个右值,但传递的是左值,也就是函数要求传递的数据是值,不是变量本身。解决办法是使用std::move
3、似乎一切顺利,麻烦来了
将list类型改为指针int*,以下这个是没有问题的
list<int*> l; typedef void (list<int*>::*fun_t)(int*&&); fun_t f = &list<int*>::push_back; int* v = nullptr; v++; (l.*f)(nullptr); (l.*f)(move(v));
另一个报错
list<int*> l; typedef void (list<int*>::*fun_t)(const int*&); fun_t f = &list<int*>::push_back; //报错 int* v = nullptr; v++; (l.*f)(nullptr); (l.*f)(move(v));
报错如下
/usr/include/c++/4.8.2/bits/stl_list.h:1020:7: note: candidates are: void std::list<_Tp, _Alloc>::push_back(std::list<_Tp, _Alloc>::value_type&&) [with _Tp = int*; _Alloc = std::allocator<int*>; std::list<_Tp, _Alloc>::value_type = int*]
push_back(value_type&& __x)
^
/usr/include/c++/4.8.2/bits/stl_list.h:1015:7: note: void std::list<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = int*; _Alloc = std::allocator<int*>; std::list<_Tp, _Alloc>::value_type = int*]
push_back(const value_type& __x)
意思是类型不匹配,有两个重载定义,一个是push_back(type&&),另一个是push_back(const type&),type是 int*
解释之前,先给出一下正确代码
list<int*> l; typedef void (list<int*>::*fun_t)(int* const &); //注意一个const位置 fun_t f = &list<int*>::push_back; int* v = nullptr; v++; (l.*f)(nullptr); (l.*f)(v);
4、一切准备妥当,开始写逻辑吧,先来个错误的版本
list<int*> l; typedef void (list<int*>::*fun_t)(int* const &); bool back = true; fun_t f = back ? &list<int*>::push_back : &list<int*>::push_front; //编译错误 int* v = nullptr; v++; (l.*f)(nullptr); //使用 (l.*f)(v); //使用
错误信息:error: address of overloaded function with no contextual type information
原因很简单,三元表达式先计算值,然后赋值给变量。在计算值时,并不知道会赋值给谁,对于重载,无法选取对应类型的,解决办法就是取地址时做一下转换。
5、完结,正确代码见开头。
- 【理论实践】指向类模板函数的指针的使用(以std::list为例)
- 指向模板类成员函数的函数指针
- 指向模板类成员函数的函数指针
- typedef使用(指向函数的指针)
- 使用指向函数的指针
- CArray 以 std::list 为元素的引发异常
- 指向函数的指针的使用
- 定义指向模板函数的函数指针类型
- 指向指针(函数)的指针
- 指向函数的指针
- 指向函数的指针
- 指向函数的指针
- 指向函数的指针
- 指向函数的指针
- 指向函数的指针
- 指向函数的指针
- 指向函数的指针
- 指向函数的指针
- unity中三种调用其他脚本函数的方法
- Python自学手册笔记(二)
- jsp中getAttribute()和getParameter的区别
- python-super
- CentOS系统rpm安装gcc
- 【理论实践】指向类模板函数的指针的使用(以std::list为例)
- easyui格式化列
- AGC018:Coins(优先队列 & 思维)
- 解决本地上传远程的冲突两种方式的区别:git push -f origin master和git pull --rebase origin master
- js for循环
- Gif图片怎么编辑 Gif各帧图片如何分别保存
- note_cloud--单击笔记使笔记标题和内容显示在编辑区域
- LeetCode--Longest Valid Parentheses
- 【noip2010模拟赛】classroom