当我运行工具clang-tidy-3.8和cppcheck-1.72时,在跟随code下:
#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输出:
$&gt; clang-tidy -checks =&#39; *&#39; main.cpp - -std = c ++ 11
警告:初始化列表构造函数不应声明为显式[google-explicit-constructor] 显式Foo(const string_list&amp; strings)
但是,如果我删除关键字 explicit ,则cppcheck-1.72报告:
$&gt; cppcheck main.cpp --language = c ++ --std = c ++ 11 --enable = all
(风格)Class&#39; Foo&#39;有一个构造函数,其中一个参数不明确。
我在Google Cpp Guide阅读:
无法使用单个参数调用的构造函数通常应省略显式。采用单个std :: initializer_list参数的构造函数也应省略显式,以支持复制初始化(例如MyType m = {1,2};)。
哪个工具是正确的 根据C ++标准?
答案 0 :(得分:0)
正如@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)
(或任何其他标准容器)未标记为 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){...}
并使用选项 cppcheck
运行 --inline-supp
。