简体   繁体   English

cppcheck 与 clang-tidy :显式构造函数 initializer_list

[英]cppcheck vs clang-tidy : explict constructor initializer_list

When I run the tools clang-tidy-3.8 and cppcheck-1.72, under the follow code :当我运行工具 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;
        }
    }
};

The clang-tidy-3.8 outputs: clang-tidy-3.8 输出:

$ > clang-tidy -checks='*' main.cpp -- -std=c++11 $ > clang-tidy -checks='*' main.cpp -- -std=c++11

warning: initializer-list constructor should not be declared explicit [google-explicit-constructor] explicit Foo(const string_list& strings)警告:初始化列表构造函数不应被声明为显式 [google-explicit-constructor] 显式 Foo(const string_list& strings)

However, if I remove the keyword explicit , the cppcheck-1.72 reports:但是,如果我删除关键字explicit ,则 cppcheck-1.72 报告:

$ > cppcheck main.cpp --language=c++ --std=c++11 --enable=all $ > cppcheck main.cpp --language=c++ --std=c++11 --enable=all

(style) Class 'Foo' has a constructor with 1 argument that is not explicit. (style) Class 'Foo' 有一个带有 1 个非显式参数的构造函数。

I read at Google Cpp Guide :我在Google Cpp 指南中读到:

Constructors that cannot be called with a single argument should usually omit explicit.不能用单个参数调用的构造函数通常应该省略显式。 Constructors that take a single std::initializer_list parameter should also omit explicit, in order to support copy-initialization (eg MyType m = {1, 2};).采用单个 std::initializer_list 参数的构造函数也应省略显式,以支持复制初始化(例如 MyType m = {1, 2};)。

Which tool is correct according the C++ standard?根据 C++ 标准,哪个工具是正确的?

As @KerrekSB said it depends on what style of construction you want to enforce.正如@KerrekSB 所说,这取决于您要执行的构建风格。

If you make the initializer list constructor explicit then如果您使初始化列表构造函数explicit

  • you are disallowing YourType A = {a, b, c};你不允许YourType A = {a, b, c}; . .
  • but only allowing YourType A({a, b, c});但只允许YourType A({a, b, c}); (or YourType A{{a, b, c}}; ) (I think some compilers accept YourType A{a, b, c} but I find it inconsistent.) (或YourType A{{a, b, c}}; )(我认为有些编译器接受YourType A{a, b, c}但我发现它不一致。)

If you don't mark it explict both cases are allowed.如果您不将其标记为explict这两种情况都是允许的。

Some people advocate for never using = in constructors (of classes) (not even for initializer list argument), so this is ultimately the style you are enforcing by marking explicit .有些人主张永远不要在(类的)构造函数中使用= (甚至不用于初始化列表参数),因此这最终是您通过标记explicit强制执行的样式

Another important side effect of marking explicit that you have to take into account is that you won't be able to pass raw initializer lists as function argument in place of the constructed object (which might be limiting but can be part of further style considerations).您必须考虑的另一个explicit标记的重要副作用是,您将无法将原始初始值设定项列表作为函数参数传递来代替构造对象(这可能是限制性的,但可以作为进一步样式考虑的一部分) . Eg fun(arg1, arg2, {a, b, c}) vs. fun(arg1, arg2, YourType({a, b, c})) .例如fun(arg1, arg2, {a, b, c})fun(arg1, arg2, YourType({a, b, c}))

Also note for example that std::vector::vector(std::initializer_list) (or any other std container) is not marked explicit .还要注意,例如std::vector::vector(std::initializer_list) (或任何其他 std 容器)标记为explicit


My rule of thumb is that I allow = in constructors when the right-hand-side can be represented "faithfully" with the constructed type and at a low computational complexity (eg less than O(N log N) or O(N^2)).我的经验法则是,当右侧可以用构造类型“忠实地”表示并且计算复杂度较低(例如小于 O(N log N) 或 O(N^2) 时,我允许在构造函数中使用= ))。 IMO there are not many cases where this can be done with an initializer list. IMO 没有多少情况可以通过初始化列表来完成。 The only examples I encountered is for 1) some reincarnation of arrays or list (including std::vector ) 2) unordered linear containers (but IMO excluding ordered containers).我遇到的唯一例子是 1) 一些数组或列表的转世(包括std::vector )2)无序线性容器(但 IMO 不包括有序容器)。 3) Multidimensional arrays (Nested initializer list). 3) 多维数组(嵌套初始化列表)。 4) Tuples (although there are non-homogeneous initializer list in the language). 4) 元组(尽管语言中有非同构的初始化列表)。

(With this rule, I think it is a mistake that it is not explicit for std::set , because std::set will reordered behind the scenes). (根据这条规则,我认为std::set不明确是错误的,因为std::set会在幕后重新排序)。


What I do in practice is to have a comment with an inline suppression of the cppcheck warning, I feel that a comment is necessary anyway for any implicit single-argument constructor.我在实践中所做的是使用内联抑制cppcheck警告进行注释,我觉得无论如何对于任何隐式单参数构造函数都需要注释。

    // cppcheck-suppress noExplicitConstructor ; because human-readable explanation here
    YourType(std::initializer_list<value_type> il){...}

and run cppcheck with the option --inline-supp .并使用选项--inline-supp运行cppcheck

(see http://cppcheck.sourceforge.net/manual.pdf#page=19 ) (见http://cppcheck.sourceforge.net/manual.pdf#page=19

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM