[英]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.