modernize-use-auto¶
此检查负责使用 auto
类型说明符进行变量声明,以提高代码可读性和可维护性。例如
std::vector<int>::iterator I = my_container.begin();
// transforms to:
auto I = my_container.begin();
auto
类型说明符仅在变量类型与初始化表达式类型匹配的情况下引入。换句话说,auto
应该推断出与源代码中最初拼写的类型相同的类型。但是,并非所有情况都应该进行转换
int val = 42;
InfoStruct &I = SomeObject.getInfo();
// Should not become:
auto val = 42;
auto &I = SomeObject.getInfo();
在此示例中,对内置类型使用 auto
不会提高可读性。在其他情况下,它会使代码的自我说明性降低,从而损害可读性和可维护性。因此,auto
仅在下面描述的特定情况下使用。
迭代器¶
迭代器类型说明符往往很长,并且经常使用,尤其是在循环结构中。由于生成迭代器的函数具有通用格式,因此可以替换类型说明符,而不会模糊代码含义,同时提高可读性和可维护性。
for (std::vector<int>::iterator I = my_container.begin(),
E = my_container.end();
I != E; ++I) {
}
// becomes
for (auto I = my_container.begin(), E = my_container.end(); I != E; ++I) {
}
只有在满足以下所有条件时,检查才会替换迭代器类型说明符
迭代器是
std
命名空间中的标准容器之一数组
双端队列
前向列表
列表
向量
映射
多映射
集
多集
无序映射
无序多映射
无序集
无序多集
队列
优先队列
栈
迭代器是标准容器的可能迭代器类型之一
迭代器
反向迭代器
常量迭代器
常量反向迭代器
除了直接使用迭代器类型外,还允许使用类型定义或其他引用这些类型的方式。但是,对于其类型如
std::vector<int>::iterator
本身是类型定义的实现特定类型将不会进行转换。请考虑以下示例
// The following direct uses of iterator types will be transformed.
std::vector<int>::iterator I = MyVec.begin();
{
using namespace std;
list<int>::iterator I = MyList.begin();
}
// The type specifier for J would transform to auto since it's a typedef
// to a standard iterator type.
typedef std::map<int, std::string>::const_iterator map_iterator;
map_iterator J = MyMap.begin();
// The following implementation-specific iterator type for which
// std::vector<int>::iterator could be a typedef would not be transformed.
__gnu_cxx::__normal_iterator<int*, std::vector> K = MyVec.begin();
正在声明的变量的初始化程序不是花括号初始化列表。否则,使用
auto
将导致变量的类型被推断为std::initializer_list
。
新表达式¶
通常,当声明一个指针并使用 new
初始化时,指向对象类型的类型会在两个地方写出:在声明类型中以及在 new
表达式中。在这种情况下,可以将声明类型替换为 auto
,从而提高可读性和可维护性。
TypeName *my_pointer = new TypeName(my_param);
// becomes
auto *my_pointer = new TypeName(my_param);
如果满足以下条件,检查还会替换多个声明中的声明类型
所有声明的变量都具有相同的类型(即,它们都是指向相同类型的指针)。
所有声明的变量都使用
new
表达式初始化。所有新表达式的类型与声明类型的指向对象类型相同。
TypeName *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;
// becomes
auto *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;
强制转换表达式¶
通常,当声明一个变量并使用强制转换进行初始化时,变量类型会在两个地方写出:在声明类型中以及在强制转换表达式中。在这种情况下,可以将声明类型替换为 auto
,从而提高可读性和可维护性。
TypeName *my_pointer = static_cast<TypeName>(my_param);
// becomes
auto *my_pointer = static_cast<TypeName>(my_param);
检查处理 static_cast
、dynamic_cast
、const_cast
、reinterpret_cast
、函数式强制转换、C 风格强制转换以及行为类似于强制转换的函数模板,例如 llvm::dyn_cast
、boost::lexical_cast
和 gsl::narrow_cast
。如果第一个模板参数是显式的并且是类型,并且函数返回该类型或指向该类型的指针或引用,则函数模板的调用被认为是类似于强制转换的行为。
已知限制¶
如果初始化程序是显式转换构造函数,则检查不会替换类型说明符,即使这样做是安全的。
目前不支持用户定义的迭代器。
选项¶
- MinTypeNameLength¶
如果选项设置为非零值(默认值为 5),则检查将忽略长度小于选项值的类型名。该选项仅影响表达式,不影响迭代器。多词类型名(
long int
)之间的空格被视为一个词。如果RemoveStars
选项(见下文)设置为 true,则类型中的*s
也被计入类型名的一部分。
// MinTypeNameLength = 0, RemoveStars=0
int a = static_cast<int>(foo()); // ---> auto a = ...
// length(bool *) = 4
bool *b = new bool; // ---> auto *b = ...
unsigned c = static_cast<unsigned>(foo()); // ---> auto c = ...
// MinTypeNameLength = 5, RemoveStars=0
int a = static_cast<int>(foo()); // ---> int a = ...
bool b = static_cast<bool>(foo()); // ---> bool b = ...
bool *pb = static_cast<bool*>(foo()); // ---> bool *pb = ...
unsigned c = static_cast<unsigned>(foo()); // ---> auto c = ...
// length(long <on-or-more-spaces> int) = 8
long int d = static_cast<long int>(foo()); // ---> auto d = ...
// MinTypeNameLength = 5, RemoveStars=1
int a = static_cast<int>(foo()); // ---> int a = ...
// length(int * * ) = 5
int **pa = static_cast<int**>(foo()); // ---> auto pa = ...
bool b = static_cast<bool>(foo()); // ---> bool b = ...
bool *pb = static_cast<bool*>(foo()); // ---> auto pb = ...
unsigned c = static_cast<unsigned>(foo()); // ---> auto c = ...
long int d = static_cast<long int>(foo()); // ---> auto d = ...
- RemoveStars¶
如果选项设置为 true(默认值为 false),则检查在将类型名替换为
auto
时,将从非类型定义指针类型中删除星号。否则,检查将保留星号。例如
TypeName *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;
// RemoveStars = 0
auto *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;
// RemoveStars = 1
auto my_first_pointer = new TypeName, my_second_pointer = new TypeName;