std::type_info
是一个简单的类,尽管填充它需要typeinfo
:编译器构造。
同样,异常是普通对象,但抛出异常需要编译器魔法(异常在哪里分配?)。
std::initializer_list
对我来说,问题是“如果没有编译器魔法,我们离 s 有多近?”
查看wikipedia,std::initializer_list<typename T>
可以通过看起来很像数组文字的东西来初始化。让我们尝试给我们std::initializer_list<typename T>
一个接受数组的转换构造函数(即,一个接受单个参数的构造函数T[]
):
namespace std {
template<typename T> class initializer_list {
T internal_array[];
public:
initializer_list(T other_array[]) : internal_array(other_array) { };
// ... other methods needed to actually access internal_array
}
}
同样,使用 a 的类std::initializer_list
通过声明一个接受单个std::initializer_list
参数的构造函数来实现这一点——也就是转换构造函数:
struct my_class {
...
my_class(std::initializer_list<int>) ...
}
所以这一行:
my_class m = {1, 2, 3};
导致编译器认为:“我需要为 ; 调用一个构造函数my_class
;my_class
有一个接受 a 的构造函数std::initializer_list<int>
;我有一个int[]
文字;我可以将 an 转换int[]
为 a std::initializer_list<int>
;我可以将它传递给my_class
构造函数”(请阅读到末尾在告诉我 C++ 不允许链接两个隐式用户定义转换之前的答案)。
那么这有多接近呢?首先,我缺少初始化列表的一些特性/限制。我不强制执行的一件事是初始化列表只能用数组文字构造,而我initializer_list
也接受一个已经创建的数组:
int arry[] = {1, 2, 3};
my_class = arry;
此外,我没有打扰右值引用。
最后,这个类只有在编译器隐式地将两个用户定义的转换链接在一起时才能按照新标准所说的那样工作。这在正常情况下是特别禁止的,所以这个例子仍然需要编译器的魔法。但我认为(1)类本身是一个普通类,(2)所涉及的魔法(强制“数组文字”初始化语法并允许隐式链接两个用户定义的转换)比看起来要少乍一看。