考虑如下代码:
int main(){ int x = 1; //int y = (1); //无用 int z = { 1 }; int a; //没有初始化器,不考虑 int b(1); int c{ 1 }; }
眼花缭乱的初始化语法。带初始化器的,基本就是:=1 (1) ={1} 或 {1} 这几种情况。变量名字和初始化器的分隔符是:= () {}这三种
#include <iostream> class S { public: S(std::initializer_list<int> il) { std::cout << "S(std::initializer_list<int> il) called" << std::endl; } S(int i) { std::cout << "S(int i) called" << std::endl; } }; int main(){ S y = 1; S z = { 1 }; S a(1); S b{ 1 }; }
我们发现,对于用户定义类型,具有{} 初始化器的,优先匹配S(std::initializer_list<int> il)。这给人提了个醒,{}不是那么万能的初始化语法。如果想调用S(int)这个构造函数,还是要老实的用传统的S a(1)语法。
#include <boost/type_index.hpp> #include <iostream> int main() { auto x = (1); auto y = 1; auto z = { 1 }; auto a(1); auto b{ 1 }; using boost::typeindex::type_id_with_cvr; std::cout << type_id_with_cvr< decltype(x)>().pretty_name() << ‘\n‘; std::cout << type_id_with_cvr< decltype(y)>().pretty_name() << ‘\n‘; std::cout << type_id_with_cvr< decltype(z)>().pretty_name() << ‘\n‘; std::cout << type_id_with_cvr< decltype(a)>().pretty_name() << ‘\n‘; std::cout << type_id_with_cvr< decltype(b)>().pretty_name() << ‘\n‘; }
auto使用另外的规则,={1} 会推导成std::initializer_list<int>{1} 而{1}会推导成 (int)1
总结:基本类型int: ={1} {1} 推导成 (int)1
自定义类型: ={1} {1} 推导成std::initializer_list<int>{1} 注:前提是自定义类型构造函数有std::initializer_list为参数的构造函数,就像S定义的那样。
auto的情况: ={1} 推导成std::initializer_list<int>{1}
{1} 推导成(int)1
规则还是比较复杂难记的,所以遇到{}初始化器还是小心为妙。