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_castdynamic_castconst_castreinterpret_cast、函数式强制转换、C 风格强制转换以及行为类似于强制转换的函数模板,例如 llvm::dyn_castboost::lexical_castgsl::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;