泛型程序设计实例(一)
来源:互联网 发布:新晨科技 知乎 编辑:程序博客网 时间:2024/05/24 05:03
- 问题提出
- 直接思维
- 泛型思维
- 作死思维
- 瞬间爆炸
问题提出
假如我有三种矩阵,3行3列,1行9列,9行1列,我希望在输出的时候
- 3行3列
0 0 00 0 00 0 0
- 1行9列
0 0 0 0 0 0 0 0 0
- 9行1列
000000000
直接思维
最直接的设计应该是这样子的:
// m_model 表示哪一种矩阵// Square 代表3行3列// Horizontal 代表1行9列// Vertical 代表9行1列// m_numbers 表示内部数组void Matrix::showMatrix() const { switch(this->m_model) { case MatrixModel::Square: { for(auto index = 0; index != 9; ++index) { std::cout << this->m_numbers[index] << ((index+1)%3==0 ? '\n':' '); } std::cout << std::endl; break; } case MatrixModel::Horizontal: { for(auto index = 0; index != 9; ++index) { std::cout << this->m_numbers[index] << ' '; } std::cout << std::endl; break; } case MatrixModel::Vertical: { for(auto index = 0; index != 9; ++index) { std::cout << this->m_numbers[index] << '\n'; } std::cout << std::endl; break; } default: { break; } }}
泛型思维
观察以上代码,发现语义上有重复的地方:
// 遍历for(auto index = 0; index != 9; ++index) { // 输出 ... // 条件输出 // 结束换行}
从代码上直观的看,只有一部分不相同:
// << ((index+1)%3==0 ? '\n':' ');// << ' ';// << '\n';
那么我们将这三个部分单独包装起来,什么!你不知道用什么包装?就地闭包啊!
// 对于第一个:[] () { static int index = 1; return ((index++)%3==0 ? '\n':' ');}// 对于第二个:[] () { return ' ';}// 对于第三个:[] () { return '\n';}
剩下三个都一样的部分,还是就地闭包:
auto output = [this]() { for(auto i : this->m_numbers) { std::cout << i; } std::cout << std::endl;};
然后怎么把这两个东西用到一起,借助 std::function:
auto output = [this](std::function<char(void)> func) { for(auto i : this->m_numbers) { std::cout << i << func(); } std::cout << std::endl;};
最后组合到一起:
void Matrix::showMatrix() const { auto output = [this](std::function<char(void)> func) { for(auto i : this->m_numbers) { std::cout << i << func(); } std::cout << std::endl; }; switch(this->m_model) { case MatrixModel::Square: { output([](){ static int index = 1; return ((index++)%3==0 ? '\n':' '); }); break; } case MatrixModel::Horizontal: { output([](){ return ' '; }); break; } case MatrixModel::Vertical: { output([](){ return '\n'; }); break; } default: { break; } }}
作死思维
然后我们注意到,switch case 的影响结果其实和 output 闭包没有一点关系,它的结果只影响三个子闭包,所以我们是不是可以考虑只编译一次 output 闭包?
那就把 switch case 和它有关的部分绑定到一起:
int index = 1;auto select = [this,&index](){ switch(this->m_model) { case MatrixModel::Square: { return ((index++)%3==0 ? '\n':' '); } case MatrixModel::Horizontal: { return ' '; } case MatrixModel::Vertical: { return '\n'; } default: { break; } }};output(select);
这样子,看上去好晦涩的写法:),其实也就是俩闭包:
void Matrix::showMatrix() const { auto output = [this](std::function<char(void)> func) { for(auto i : this->m_numbers) { std::cout << i << func(); } std::cout << std::endl; }; int index = 1; auto select = [this,&index](){ switch(this->m_model) { case MatrixModel::Square: { return ((index++)%3==0 ? '\n':' '); } case MatrixModel::Horizontal: { return ' '; } case MatrixModel::Vertical: { return '\n'; } default: { break; } } }; output(select);}
瞬间爆炸
是否还记得模板参数推导和模板特化,我试图将 switch 的过程移动到编译期,也就是说在运行期就不需要再 switch 考虑了
// 首先定义主模板template <MatrixModel model>void Matrix::show() const { std::cout << "None" << std::endl;}// 特化为 Square 的情况template <>void Matrix::show<MatrixModel::Square>() const { std::cout << "Square" << std::endl; int index = 0; for(auto i : this->m_numbers) { std::cout << i << ((index++)%3==0 ? '\n':' '); } std::cout << std::endl;}// 特化为 Horizontal 的情况template <>void Matrix::show<MatrixModel::Horizontal>() const { std::cout << "Horizontal" << std::endl; for(auto i : this->m_numbers) { std::cout << i << ' '; } std::cout << std::endl;}// 特化为 Vertical 的情况template <>void Matrix::show<MatrixModel::Vertical>() const { std::cout << "Vertical" << std::endl; for(auto i : this->m_numbers) { std::cout << i << '\n'; } std::cout << std::endl;}
然而这样子问题就来了,导致了在编译期由我们决定要按何种形式显示:
matrix.show<MatrixModel::Square>();matrix.show<MatrixModel::Horizontal>();matrix.show<MatrixModel::Vertical>();
对此,我只能说:WTF!到此为止!
CSDN 辣鸡 MD 编辑器,无序列表格式全丢
阅读全文
1 0
- 泛型程序设计实例(一)
- CPU卡程序设计实例(一)电路
- 泛型程序设计实例(二)
- java-泛型程序设计(一)
- javascript 高级程序设计(一) 正则表达 RegExp实例属性
- 杨季文 80x86汇编语言程序设计 实例一
- 【java核心技术卷一】泛型程序设计
- 汇编语言程序设计(一)
- Windows程序设计(一)
- 数组程序设计(一)
- 函数程序设计(一)
- 程序设计概述(一)
- Servlet程序设计(一)
- C#程序设计(一)
- ACM程序设计(一)
- Shell程序设计(一)
- Java程序设计(一)
- shell程序设计(一)
- 九度 题目1350:二叉树的深度
- 关于安卓无线定位与定位算法的讨论
- html5前端框架
- 开篇博客
- Android-AsyncTask
- 泛型程序设计实例(一)
- FAFU OJ 博弈(8)Couple doubi
- MTK断点调试的几种方法
- The :java.lang.UnsatisfiedLinkError: Can't find dependent libraries
- 纯CSS实现垂直居中的几种方法
- 思想决定你走什么样的路
- 动态规划实例(五):0-1背包问题(整包背包)
- Hyper-v虚拟机配置内部虚拟交换机
- 统计自然语言处理(词汇获取)