std::type_info
是一个简单的类,尽管填充它需要typeinfo
:编译器构造。
同样,异常是普通对象,但抛出异常需要编译器魔法(异常在哪里分配?)。
对我来说,问题是“我们能有多接近std::initializer_list
没有编译器魔法吗?”
看着维基百科 http://en.wikipedia.org/wiki/C%2B%2B0x#Initializer_lists, 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
}
}
同样,一个类使用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
有一个构造函数,它需要一个std::initializer_list<int>
;我有一个int[]
文字;我可以转换一个int[]
to a std::initializer_list<int>
;我可以将其传递给my_class
构造函数”(在告诉我 C++ 不允许链接两个隐式用户定义转换之前,请阅读答案的末尾).
那么这有多接近呢?首先,我缺少初始化列表的一些功能/限制。我不强制执行的一件事是初始化列表只能用数组文字构造,而我的initializer_list
也将接受一个已经创建的数组:
int arry[] = {1, 2, 3};
my_class = arry;
此外,我没有费心去搞乱右值引用。
最后,如果编译器隐式地将两个用户定义的转换链接在一起,则此类只能按照新标准规定的方式工作。这在正常情况下是被明确禁止的,因此该示例仍然需要编译器魔法。但我认为(1)类本身是一个普通类,并且(2)所涉及的魔力(强制执行“数组文字”初始化语法并允许两个用户定义的转换隐式链接)比看起来要少乍一看。