要开新坑了,而且是个对我来说很大的项目,自己一个人完成,开发周期较长,而且期望在学术圈能有很多人用到,所以正式来看看代码规范。Google 的这个代码规范是比较著名的之一。但代码规范并非这一个标准就规定死的,具体使用哪些规则还要看团队的偏好以及既有代码的规范。
本文总结了 Google C++ Style Guide 中比较常用的规则,而且经过简化。如果想查看完整的规范,请移步 原始网页。
.cc
文件都应该对应这一个 .h
文件。除非某些 .cc
用于单元测试或者仅包含类似 main()
。header guards
,使用 #define
方式,变量名字使用 <PROJECT>_<FULLPATH>_<FILE>_H_
以确保绝对的唯一性,例如: #ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
...
#endif // FOO_BAR_BAZ_H_
.cc
文件中定义。 .cc
文件中使用 Forward Declarations
,即那些只有声明没有定义的情况,典型代表就是 extern
。using namespace foo
这种用法。namespace baz = ::foo::bar::baz;
,除非定义在只在内部使用的代码块中。static
,这样别的文件中的同名变量等就会是完全独立的另一个实体。不要在头文件中使用这个用法。if
,while
和 for
语句体中使用的变量可以在这些语句的适当位置进行定义,但某些对象除外(可能会损失性能)。比如: while (const char* p = strchr(str, '/'))
str = p + 1;
thread_local
变量需要在编译时就进行初始化,以避免部分线程没有初始化的问题。explicit
关键字,避免隐式类型转换。但在逻辑上就可以互换的类型、拷贝和转移(move)构造函数、以及接受一个初始化列表的构造函数不用这种方式。delete
标记不可用。struct
,其他的所有情况都是用 class
,尽管他们在 C++ 中的行为几乎一样。Pair
和 Tuple
,其他情况优先使用 struct
。private
和 protected
继承;多继承的时候最好只继承纯虚类。override
或者 final
关键字以避免很多低级错误。private
的,常量除外。声明的时候尽量分组书写,将相似的放在一起,而且 public
的放在前面。建议的声明顺序为:typedef
,using
,enum
,内嵌结构体或者类定义,常量,工厂函数,构造函数,赋值运算符,析构函数,其他函数,最后是数据成员。return
作为函数输出的手段。const
引用/指针,必须的输出参数或者输入/输出参数使用引用/指针传递,其他的使用普通引用/指针传递。std::forward
的时候;重载函数,与 const Foo&
搭配。static_cast
或者初始化列表 int64_t y = int64_t{1}
。其他的还有 const_cast
和 reinterpret_cast
。++i
,--i
。const
和 constexpr
。##
生成各种名字。nullptr
表示空指针,'\0'
表示空字符(而不是 0
)sizeof(varname)
而不是 sizeof(type)
,这样更加不容易出错。auto
),不要仅仅因为懒得写类型名字图方便而使用。n
可以被用于五行左右的函数里,但要是放在一个类中,那它的意思就很模糊了。camel case
的时候仅仅让首字母大写,比如 StartRpc()
而不是 StartRPC()
。_
或者短横线 -
,更优先使用下划线。a_class_data_member_
。k
开头,大小写混合,必要时使用下划线连接。//
或者 /* */
形式,但要一致。.h
和 .cc
文件的开头注释只保留一处。TODO
注释。函数声明:返回值类型和函数名在同一行,参数尽量也在同一行,如果太长可以换行,但要对齐,例如:
ReturnType ClassName::ReallyLongFunctionName(Type par_name1, Type par_name2,
Type par_name3) {
DoSomething();
...
}
// 如果第一个参数都无法容下
ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
Type par_name1, // 4 space indent
Type par_name2,
Type par_name3) {
DoSomething(); // 2 space indent
...
}
if
和左括号之间加空格,右括号和左花括号也要有空格,但括号和里面的条件语句之间没有空格。如果其中包含初始话语句,要么放在一行里,要么在分号之后换行。 else
或者 else if
而且语句体只有一行语句,那么可以省略花括号,可以放在一行也可以分开两行。case
的语句体可以使用花括号括起来,但左括号要和 case
语句在同一行,且右花括号自己占一行。continue
语句。*
和 &
符号后面也没有空格(但前面可以有)。注意风格的一致性。 布尔表达式:需要换行的时候要注意换行位置的一致性,下面的例子中都在 &&
符号之后换行:
if (this_one_thing > this_other_thing &&
a_third_thing == a_fourth_thing &&
yet_another && last_one) {
...
}
#
之后的空格可有可无。public
,protected
,private
的顺序写,前后缩进一个空格(默认缩进距离是 2 个空格),前面有空行,但后面不需要空行for
循环的分号后面要有,range-based for
循环中的冒号前后要有switch
语句中冒号前面没有空格,但后面如果有代码则可以加一个空格<
前面没有空格,>(
这两个中间也没有