[Add]
Lambda expressions
在合适的时候使用lambda表达式; 不要使用默认的lambda captures, 使用显式的captures;
[http://en.cppreference.com/w/cpp/language/lambda ]
定义:
lambda表达式是一个创建匿名函数对象anonymous function objects.的简洁concise方式; 在将函数作为参数传递的时候很有用;
1
2
3
|
std::sort(v.begin(), v.end(), [](
int
x,
int
y) {
return
Weight(x) < Weight(y);
});
|
Lambda由C++11的一系列功能utility引入, 作用于函数对象function object, 例如多态的polymorphic封装 std::function;
优点:
- lambda比其他定义函数对象传递给STL算法的方式要简洁concise很多, 对可读性是一个很好的改善;
- lambda, std::function, std::bind可以组合使用在一般的回调机制中: callback mechanism; 它们使得写出将bound函数作为参数的函数更容易;
缺点:
- 变量捕捉variable capture在lambda中是棘手的tricky, 而且可能是产生野指针dangling-pointer的新的源头; [http://en.wikipedia.org/wiki/Dangling_pointer]
- 使用lambda可能会失控, 很长的嵌套匿名函数nested anonymous function可能会让代码难以理解;
结论:
- 在合适的时候使用lambda表达式, 按照下面将讨论的格式书写;
- 不要使用default capture; 显式地书写lambda capture; 例如, 不要写 [=](int x){ return x + n;} 而应该写 [n](int x){ return x + n;} 这样读者可以立即看到 n是正在被捕获captured(按值);
- 未命名的lambda保持简短; 如果一个lambda body超过了5行, 建议给一个名字, 或者使用一个命名函数代替lambda;
- 如果可以让读者看起来更清晰, 显式地指定lambda的返回类型; 就像auto中说到的;
<<<
[Add]
模板元編程 Template metaprogramming
防止复杂的模板编程;
定义:
Template metaprogramming指的是一种技术科目, 利用exploit了C++模板实例化机制是图灵完备Turing complete的事实, 可以用来在类型领域进行任意的arbitrary 编译时计算;
优点:
Template metaprogramming允许极度灵活的flexible接口, 而且是类型安全及性能高效的; 对于Google Test, std::tuple, std::function, Boost这样的工具, 它几乎是必须的;
[http://en.cppreference.com/w/cpp/utility/tuple http://en.cppreference.com/w/cpp/utility/functional/function ]
缺点:
用在Template metaprogramming中的技术除了语言专家之外, 多数人难以搞清楚; 使用复杂模板的代码经常难以读懂, 很难debug或维护;
Template metaprogramming可能会导致极糟糕的编译时错误消息error message: 即使接口是简单的, 但当用户做错某些事情的时候复杂的实现细节就会显现;
Template metaprogramming会影响大范围的重构refactor, 使得重构工具难以应用; 首先, 模板代码需要多个上下文环境 context来进行扩展, 而且难以判定这些转换对所有情况都有意义; 其次, 一些通过AST[抽象语法树http://en.wikipedia.org/wiki/Abstract_syntax_tree]来工作的重构根据只能表现经过模板扩展template expansion之后的代码结构; 对于需要重写rewritten的原始代码结构来说很难做到自动化;
结论:
有时候Template metaprogramming可以让接口更清晰, 更易于使用, 但有时也会导致聪明过头overly clever; 最好是在一个小范围的低层组件component中使用, 在那里额外的维护负担被分散到大量的使用中;
使用Template metaprogramming或其复杂的模板技术前要仔细考虑, 考虑清楚你团队中成员的平均水平是否能对代码有足够的理解, 等你转到其他项目时他们能够维护项目, 或者是否一个非C++程序员能轻松浏览代码, 理解那些error message或者跟踪trace到那些他们想要调用的函数流;
如果你使用了递归的recursive模板实例化或者类型列表type list或者元功能metafunction或者表达式模板expression templates, 或者依赖SFINAE, 或sizeof技巧trick来检测函数重载决议overload resolution, 那么你很有可能走的太远了;
[http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error ]
如果你使用Template metaprogramming, 应该期望的是将相当的considerable努力effort放在把复杂性最小化和独立化上; 你应该尽可能将metaprogramming作为一个实现细节隐藏起来, 这样用户使用的headers可读性较好, 你也应该保证那些tricky code都有完备的注释; 要仔细地将代码如何使用的文档写好, 应该要写出"生成generated"的代码会是什么样子的;
要小心用户犯错时编译器会提示的那些error message; error message也是用户接口的一部分, 你的代码应当尽可能调整tweaked 那些error message, 成为对用户来说可理解, 可进行下一步改动的信息;
<<<
5.17 Boost库
Tip 只使用Boost中被认可的库;
定义:
Boost库集是一个广受欢迎, 经过同行鉴定, 免费开源的C++库集; [http://www.boost.org/]
优点:
Boost代码质量普遍较高, 可移植性好, 填补了C++标准库很多空白, 如型别的特性type trait; 更完善的绑定器binder;
[Remove]更好的智能指针; 同时还提供了TR1(标准库扩展)的实现; <<<
缺点:
某些Boost库提倡的编程实践可读性差; 比如元编程metaprogramming和其他高级模板技术, 以及过度"函数化functional"的编程风格;
结论:
为了向阅读和维护代码的人员提供更好的可读性, 我们只允许使用Boost一部分经认可的特性子集subset; 目前允许使用以下库:
- Compressed Pair: boost/compressed_pair.hpp (http://www.boost.org/doc/libs/1_56_0/libs/utility/doc/html/compressed_pair.html)
- The Boost Graph Library(BGL): boost.graph (序列化除外adj_list_serialize.hpp), parallel/distributed algorithms and data structures (boost/graph/parallel/* and boost/graph/distributed/*) (http://www.boost.org/doc/libs/1_56_0/libs/graph/doc/index.html)
- Property Map: boost/property_map.hpp 除了parallel/distributed property maps (boost/property_map/parallel/*) (http://www.boost.org/doc/libs/1_56_0/libs/property_map/doc/property_map.html)
- Iterator 中处理迭代器定义的部分: boost/iterator/iterator_adaptor.hpp, boost/iterator/iterator_facade.hpp, and boost/function_output_iterator.hpp (http://www.boost.org/doc/libs/1_56_0/libs/iterator/doc/index.html)
[Add]
- Call Traits boost/call_traits.hpp http://www.boost.org/doc/libs/1_57_0/libs/utility/call_traits.htm
- Polygon 中处理Voronoi diagram构造而且不依赖于其余Polygon的部分 boost/polygon/voronoi_builder.hpp, boost/polygon/voronoi_diagram.hpp, boost/polygon/voronoi_geometry_type.hpp http://www.boost.org/doc/libs/1_57_0/libs/polygon/doc/index.htm
- Bimap from boost/bimap http://www.boost.org/doc/libs/1_57_0/libs/bimap/doc/html/index.html
- Statistical Distributions 和 Functions from boost/math/distributions http://www.boost.org/doc/libs/1_57_0/libs/math/doc/html/dist.html
- Multi-index from boost/multi_index http://www.boost.org/doc/libs/1_57_0/libs/multi_index/doc/index.html
- Heap from boost/heap http://www.boost.org/doc/libs/1_57_0/doc/html/heap.html
- The flat containers from Container: boost/container/flat_map, and boost/container/flat_set http://www.boost.org/doc/libs/1_57_0/doc/html/container.html
<<<
我们正在积极考虑增加其他Boost特性, 所以列表里的规则将不断变化;
[Add]
下面的库是允许的, 但是不鼓励使用, 因为它们在C++11中被废弃superseded;
- Array: boost/array.hpp (http://www.boost.org/doc/libs/1_56_0/doc/html/array.html) 被std::array替代 [http://en.cppreference.com/w/cpp/container/array ]
- Pointer Container: boost/ptr_container(序列化除外); (http://www.boost.org/doc/libs/1_56_0/libs/ptr_container/doc/ptr_container.html) 被std::unique_ptr替代; [http://en.cppreference.com/w/cpp/memory/unique_ptr ]
<<<
[Add]
C++11
在合适的时候使用C++11语言与库的扩展(原先是C++0x); 在项目中使用C++11特性之前要考虑到其他环境的可移植性;
定义:
C++11包含重大改动, 包括语言和库; http://en.wikipedia.org/wiki/C++11
优点:
C++11是2014 aug的官方标准, 大多数C++编译器都会支持; 它标准化了一些通用的C++扩展, 允许一些操作上的简写shorthand, 而且在一些性能和安全性上有所改进;
缺点:
C++11标准在本质上substantially比它的前辈(1300页 vs 800页)要更复杂, 更多的程序员对此陌生; 对于一些特性在长期的可读性和可维护性需要花费的努力上还不可知; 我们不能预见这各式各样的特性何时会被统一通过工具实现, 特别是对于有些强制使用旧版工具的项目来说;
对于Boost, 一些C++11的扩展鼓励编码实践即便会妨碍hamper可读性--例如移除冗余的检查(类型名称等)可能对阅读者有帮助, 或者鼓励模板元编程; 其他有些扩展通过现存的机制复制可用的功能, 可能导致混淆和转换消耗;
结论:
C++11特性可以使用, 除非另有说明unless specified otherwise; 除了在本指南余下部分描述的, C++11以下的特性不要使用:
- 具有trailing return types的Functions(不是lamdba function), e.g. 写一个 auto foo() -> int, 代替 int foo(); 要保持和现存函数声明的风格一致性;
- 编译时有理数 rational number( <ratio>), 考虑到这是一个更 template-heavy的接口风格;
- <cfenv>和<fenv.h>头文件, 许多编译器还不能完全支持;
- 默认lambda capture;
<<<
---TBC---YCR