Pitfalls

Uniform Initialization 代表通用,不管在哪裡使用都是對的。所以盡量使用 braced initialization。

braced initialization 還可以 prohibits implicit narrowing conversions among built-in types,考慮以下的例子:

 
int main() {
    double a = 3.0, b = 2.3;
    int x {a + b}; // warning: narrowing conversion of '(a + b)' from 'double' to 'int' [-Wnarrowing]
}

不過使用 braced initialization 要小心,尤其是在 class 的 constructor 中有牽涉到 std::initializer_list 時,因為 compiler 除非真的沒辦法(無法做 conversion),要不然都會優先選擇去 match 有 std::initializer_list 的 constructor,然後才會考慮一般的 overload resolution 規則。 考慮以下例子:

#include <initializer_list>
 
class Widget {
public:
	Widget(int i, bool b);
  	Widget(int i, double d);
  	Widget(std::initializer_list<long double> il);
  
};
int main()
{	
  Widget w{10, 1.0}; // 10 and 1.0 are converted to long double!
}

what to compiler sees:

#include <initializer_list>
 
class Widget
{
  
  public: 
  Widget(int i, bool b);
  
  Widget(int i, double d);
  
  Widget(std::initializer_list<long double> il);
  
};
 
 
int main()
{
  Widget w = Widget{std::initializer_list<long double>{10, static_cast<const long double>(1.0)}};
  return 0;
}

而且,braced initialization 如上所說,會幫我們做 narrowing conversion 的檢查:

#include <initializer_list>
 
class Widget {
public:
	Widget(int i, bool b);
  	Widget(int i, double d);
	Widget(std::initializer_list<bool> il);
  
};
int main()
{	
  Widget w{10, 1.0}; //  error: constant expression evaluates to 10 which cannot be narrowed to type 'bool' [-Wc++11-narrowing]
}

真的沒辦法做 conversion 的 case:

#include <initializer_list>
#include <string>
 
class Widget {
public:
	Widget(int i, bool b);
  	Widget(int i, double d);
	Widget(std::initializer_list<std::string> il);
  
};
int main()
{	
  Widget w{10, 1.0}; // Widget(int i, double d) is called!
}

Braced Initialization on Vector

#include <vector>
 
int main()
{	
  std::vector<int> V{20, 10}; // use constructor which has initializer_list! 
  std::vector<int> V2(20, 10); 
  return 0;
}

V 是一個 size = 2 的 vector,而 V2 size = 20。