XI Lint: C++风格规范
XI Lint: C++风格规范
C++11以前
注释
对于函数功能的注释请分为两个部分,对于函数的参数说明以及函数的调用功能注释应该写在函数定义的上方(方便IDE调用)。对于函数的设计说明的注释应该写在函数的{}内部
为函数类型添加注释应该包括参数而不只是返回值
//xxxxxxxx
//function1:(int,int)->void
//a:int xxxx
//b:int xxxx
void function1(int a, int b)
{
//xxxxxx
}
对于/**/
的文本注释应该使用Java Doc 风格的写法如
/**
*
*
*/
命名风格
文件名、包名:小写连续无间断 justname1
命名空间名:小写连续无间断,并且小于8个字符 name1
类名、结构体名、枚举变量名:大驼峰 PascalCase1
函数名、类成员变量名、宏替函数名:小驼峰 camelCase1
类私有变量名:头下划线_snake_case_1
局部变量名、参数变量名:小写下划线snake_case_1
全局变量名、宏替换名变量名:大驼峰 PascalCase1
常量名:全大写下划线 CONST_CASE_1
缩进风格
4个空格
行风格
每行不能有超过一个语句,以下情况除外:
变量的初始化以及初始化赋值
for语句的3个子语句
多个意义独立的代码块使用两个空行隔开
多个事实独立的代码块应该拆分函数或者使用{}作用域隔开。例如绘图中的begin和end:
begin(); {
//xxx
} end();
{
//xxx
}
导入语句、函数、成员函数、结构体、全局变量块之间用空行隔开。
大括号风格
函数大括号:左括号换行
void function1()
{
}
循环、控制、类、结构体、枚举大括号:左括号前加空格且不换行
右括号不要和下一逻辑单元并列
if (a>1) {
} //不要和else同一行
else {
}
单语句循环、控制:必须加大括号,但是右括号可以写在同一行:
if (a>1) { a++; }
if (a>1) {
a++;}
else {
a--;}
do-while语句右括号后加空格
do {
} while();
代码空格
运算符空格
对于被重写的运算符,运算符两侧必须有空格
对于没有被重写的运算符,运算符两侧可以没有空格
取地址符、取值符、引用与变量之间不能有空格
引用与指针的类型
考虑将指针与引用当作类型。
在过于复杂的时候使用typedef定义函数指针与其他二级指针。
在描述类型名时,指针符号 *
和引用符号 &
与左侧的类型名之间不能有空格,与右侧的其它关键字之间必须有一个空格,如 char* const
或 int*&
。
在定义变量、函数返回值、参数时,指针符号 *
和引用符号 &
与左侧的类型名之间不能有空格,与右侧的变量、函数、参数名之间必须有一个空格。
int* a;
int* a, * b, * c;
方法调用、命名空间引用
前后不能有空格
.
->
::
分隔符空格
,
前不能有一个空格,后要有一个空格
;
前不能有一个空格,后换行或者空格加注释
for语句 ;
前不能有一个空格,后要有一个空格 for (int i=0; i<1; i++)
括号空格
小括号
括号与内部之间不能有空格
函数名之后不能有空格
关键字之后要有一个空格
function1(1, 2);
if (a>1)
中括号
中括号与外部两侧不能有空格
中括号内部如果是一个语句,可以内部两侧都有空格
f(a[1][2])
f(a[ b[1] ][2])
大括号
见大括号的要求
宏替换风格
如果出现了使用函数无法实现的大量重复性代码,应该使用宏替换
常量优先使用const
宏替换代码保持换行和缩进(末尾加\
)
类定义风格
必须使用单继承+多继承只能接口的形式
单继承内容单行写,多继承可以换行加缩进
继承的冒号:
左右都要写空格
类的成员变量定义与成员方法定义分离
分别按照private、protect、public的顺序进行定义
优先使用virtual
class a : b {
private: //顶格写
int c,d,e;
};
循环、控制语句风格
变量定义或者变量赋值类型的if-else语句使用三目运算符代替
非表单跳转的条件控制优先使用if-else语句。或者宏替换else if(xxx) 为 cases(xxx)
表单跳转的条件控制考虑特殊情况必须首先使用if,在else语句下使用switch
循环优先使用for循环;死循环优先使用for (;;)
循环后直接接添加可以省略for循环大括号,并且写于同一行。
for (;;) if (a<1) {
}
单文件总体风格
导入区
//空行
常量定义区(包括#define)
//空行
全局变量定义区
//空行
函数定义区(包括#define)
//空行
int main {
return 0;
}
变量声明时,同一逻辑区可以同时声明(逗号隔开)
如果不同逻辑即使同一类型不要同时声明
int a,b,c;
int fromFactory;
导入区要求
优先使用标准库内容
#include
中,C 标准库头文件必须使用 c
前缀,而不是 .h
后缀
#include
中,C 标准库头文件应该放置于 C++ 标准库头文件前,其它头文件(如果有)应放置于最后
多文件风格
一个类、一个命名空间分别写于头文件和源文件,并分离。
所有成员变量和成员方法必须写入头文件。
函数的定义注释写在头文件。函数的实现注释写于源文件。
导入部分写于源文件中。
using namespace
写于源文件中。
参考Menci's Code Style for OI | Menci's OI Blog
C++11以后
使用using代替typedef
使用using std:xxx;
代替using namespace std;
仅在lambda表达式以及较为复杂的表达式中使用auto
优先使用统一的cast进行强制类型转换
使用nullptr
代替NULL
C++20(含C++11)以后
优先使用constexpr
代替宏替换
优先使用constexpr
于条件语句中
优先使用concept
代替原先接口的定义
优先使用import
代替#include
优先使用using std:xxx;
代替using namespace std;
变量声明方式
// this should be the only way to create variables
auto x=Type{ ... }; // e.g. auto x = std::vector{ 1, 2, 3 };
auto y=func(...); // e.g. auto [a, b] = something_that_returns_2_values();
auto z=/* literal */; // e.g. auto z = 42;
auto w=static_cast<Type>(/* literal */); // e.g. auto w = static_cast<int*>(nullptr);
优先使用array代替原来的数组
auto a = array{ 1, 2, 3};
函数声明方式
auto main()->int{
return 0;
}
函数模版使用概念优先使用auto的表示形式
template<typename T, auto x>
concept Selector = std::same_as<std::decay_t<T>, std::conditional_t<x >= 42, int, std::string>>;
template<auto x>
auto f(Selector<x> auto) {}
智能指针相关待定