MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
为什么?
MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
为什么?
基本上是从Bjarne Stroustrup的《C++程序设计语言第四版》复制和粘贴的:
列表初始化不允许缩小转换 (§iso.8.5.4)。也就是说:
例子:
void fun(double val, int val2) {
int x2 = val; // if val == 7.9, x2 becomes 7 (bad)
char c2 = val2; // if val2 == 1025, c2 becomes 1 (bad)
int x3 {val}; // error: possible truncation (good)
char c3 {val2}; // error: possible narrowing (good)
char c4 {24}; // OK: 24 can be represented exactly as a char (good)
char c5 {264}; // error (assuming 8-bit chars): 264 cannot be
// represented as a char (good)
int x4 {2.0}; // error: no double to int value conversion (good)
}
仅有在使用auto
关键字获得由初始化程序确定的类型时,才优先选择=而不是{}。
例如:
auto z1 {99}; // z1 is an int
auto z2 = {99}; // z2 is std::initializer_list<int>
auto z3 = 99; // z3 is an int
除非你有充分的理由,否则请优先选择使用 {} 初始化方法。
()
也可以被解析为函数声明,这是一个事实。使用T t(x,y,z);
的语法形式却不能使用T t()
的形式,这种不一致性很容易引起混淆。有时候,即使你已经明确了变量x
的值,你也不能使用T t(x);
的形式。 - juanchopanzastd::initializer_list
的构造函数类型时,大括号初始化会变得一团糟。RedXIII提到了这个问题(并只是随意地解决了它),而您完全忽略了它。A(5,4)
和A{5,4}
可能调用完全不同的函数,这是需要知道的重要事情。这甚至可能导致看起来不直观的调用。说默认应该使用{}
将导致人们误解发生的情况。虽然这不是您的错。我个人认为这是一个非常考虑不周的功能。 - user1520427auto var{ 5 }
,它将被推断为int
,而不再是std::initializer_list<int>
。 - Edoardo Dominicivector<int> a{10, 20}; //Curly braces -> fills the vector with the arguments
vector<int> b(10, 20); //Parentheses -> uses arguments to parametrize some functionality,
vector<int> c(it1, it2); //like filling the vector with 10 integers or copying a range.
vector<int> d{}; //empty braces -> default constructs vector, which is equivalent
//to a vector that is filled with zero elements
const int &b{}
<- 并不是试图创建未初始化的引用,而是将其绑定到临时的整数对象上。第二个例子:struct A { const int &b; A():b{} {} };
<- 并不是试图创建未初始化的引用(因为()
会这样做),而是将其绑定到临时的整数对象上,然后悬挂无用。即使使用-Wall
选项,GCC也不会警告第二个例子。 - Johannes Schaub - litbinitializer_list<>
构造函数更受推荐。这会在类型为 T
的构造函数既可以是初始化列表也可以是旧式的构造函数时,引发构造函数和模板问题。struct Foo {
Foo() {}
Foo(std::initializer_list<Foo>) {
std::cout << "initializer list" << std::endl;
}
Foo(const Foo&) {
std::cout << "copy ctor" << std::endl;
}
};
int main() {
Foo a;
Foo b(a); // copy ctor
Foo c{a}; // copy ctor (init. list element) + initializer list!!!
}
假设没有遇到这种类,那么就没有理由不使用初始化列表。
initializer_list
语义(以及可能用于默认构造对象)。 - Xeostd::initializer_list
规则,它只会使语言变得更加混乱和复杂。如果你想使用 std::initializer_list
构造函数,用 Foo{{a}}
不就可以了吗?这似乎比让 std::initializer_list
优先于所有其他重载函数更容易理解。 - user1520427std::initializer_list<Foo>
构造函数,但是在某个时间点上要将其添加到Foo
类中以扩展其接口,那么Foo
类的用户就会出问题。 - mipinitializer_list<>
),但并没有说明谁说它是首选,然后又提到了一个不适用的好例子。我错过了什么,因为截至2016年4月21日约有30其他人发现它很有帮助? - dwanderson-Wno-narrowing
,它才更安全。如果你这样做了,那么它就不太安全。没有这个标志,唯一不安全的情况将在C++20中得到修复。clang++ -std=c++14
告诉我:main.cpp:22:7: error: calling a private constructor of class 'Foo'
。至于隐式调用显式构造函数的论断,其实根本毫无意义。这是一个隐式构造函数调用:foo_instance = false;
。通过调用相应的构造函数,false 隐式地被转换为 Foo。如果您使用花括号,您将明确调用构造函数。重点是,如果您不提及类型名称,您不能使用花括号进行此类赋值。 - TamaMcGlinn
std::map<std::string, std::vector<std::string>>::const_iterator
想要与你交流一下。 - Xeotypedef std::map<std::string, std::vector<std::string>> MyContainer
是更加简洁的选择。对于本地范围类型,我只会使用auto
。 - mipusing MyContainer = std::map<std::string, std::vector<std::string>>;
更好(特别是因为您可以将其模板化!) - JAB