[英]cppcheck vs clang-tidy : explict constructor initializer_list
当我运行工具 clang-tidy-3.8 和 cppcheck-1.72 时,在以下代码下:
#include <initializer_list>
#include <string>
#include <iostream>
using string_list = std::initializer_list<std::string>;
class Foo {
public:
explicit Foo(const string_list& strings) {
for (const auto& ss : strings) {
std::cout << ss << std::endl;
}
}
};
clang-tidy-3.8 输出:
$ > clang-tidy -checks='*' main.cpp -- -std=c++11
警告:初始化列表构造函数不应被声明为显式 [google-explicit-constructor] 显式 Foo(const string_list& strings)
但是,如果我删除关键字explicit ,则 cppcheck-1.72 报告:
$ > cppcheck main.cpp --language=c++ --std=c++11 --enable=all
(style) Class 'Foo' 有一个带有 1 个非显式参数的构造函数。
我在Google Cpp 指南中读到:
不能用单个参数调用的构造函数通常应该省略显式。 采用单个 std::initializer_list 参数的构造函数也应省略显式,以支持复制初始化(例如 MyType m = {1, 2};)。
根据 C++ 标准,哪个工具是正确的?
正如@KerrekSB 所说,这取决于您要执行的构建风格。
如果您使初始化列表构造函数explicit
则
YourType A = {a, b, c};
.YourType A({a, b, c});
(或YourType A{{a, b, c}};
)(我认为有些编译器接受YourType A{a, b, c}
但我发现它不一致。) 如果您不将其标记为explict
这两种情况都是允许的。
有些人主张永远不要在(类的)构造函数中使用=
(甚至不用于初始化列表参数),因此这最终是您通过标记explicit
强制执行的样式。
您必须考虑的另一个explicit
标记的重要副作用是,您将无法将原始初始值设定项列表作为函数参数传递来代替构造对象(这可能是限制性的,但可以作为进一步样式考虑的一部分) . 例如fun(arg1, arg2, {a, b, c})
与fun(arg1, arg2, YourType({a, b, c}))
。
还要注意,例如std::vector::vector(std::initializer_list)
(或任何其他 std 容器)未标记为explicit
。
我的经验法则是,当右侧可以用构造类型“忠实地”表示并且计算复杂度较低(例如小于 O(N log N) 或 O(N^2) 时,我允许在构造函数中使用=
))。 IMO 没有多少情况可以通过初始化列表来完成。 我遇到的唯一例子是 1) 一些数组或列表的转世(包括std::vector
)2)无序线性容器(但 IMO 不包括有序容器)。 3) 多维数组(嵌套初始化列表)。 4) 元组(尽管语言中有非同构的初始化列表)。
(根据这条规则,我认为std::set
不明确是错误的,因为std::set
会在幕后重新排序)。
我在实践中所做的是使用内联抑制cppcheck
警告进行注释,我觉得无论如何对于任何隐式单参数构造函数都需要注释。
// cppcheck-suppress noExplicitConstructor ; because human-readable explanation here
YourType(std::initializer_list<value_type> il){...}
并使用选项--inline-supp
运行cppcheck
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.