该标准草案显示了initializer_list
的概要。它没有私人构造函数。
但是我看过的两个标准库实现,libstdc ++和libc ++都提供了私有构造函数:
// The compiler can call a private constructor.
constexpr initializer_list(const_iterator __a, size_type __l)
: _M_array(__a), _M_len(__l) { }
_LIBCPP_ALWAYS_INLINE
_LIBCPP_CONSTEXPR_AFTER_CXX11
initializer_list(const _Ep* __b, size_t __s) _NOEXCEPT
: __begin_(__b),
__size_(__s)
{}
我认为这个私有构造函数“隐含”的部分源于§8.5.4/ 5:
std::initializer_list<E>
类型的对象是由一个构造的 初始化列表,好像实现分配了一个临时数组 属于const E
的 N 元素,其中 N 是元素的数量 在初始化列表中。该数组的每个元素都是 使用初始化程序的相应元素进行复制初始化 列表,并构造std::initializer_list<E>
对象 参考那个数组。
所以我的问题是:
概要不明确吗?
库是否需要私有构造函数?编译器不能做什么?
答案 0 :(得分:2)
概要是否未明确指定?
不,它记录了initializer_list
类模板的面向用户的位,实际上允许您在代码中使用的部分。根据概要,模板只包含一个默认构造函数,允许您创建空的initializer_list
,这显然不是很有用。但是,initializer_list<T>
是依赖于编译器完成的某些 magic 的类型。通过魔术,我指的是你引用的§8.5.4/ 5。这允许以下语句合法并编译。
std::initializer_list<int> numbers{1, 2, 3, 4}; // no such constructor in the synopsis
这里,如§8.5.4/ 5中所述,编译器将创建一个包含四个整数的数组,然后用一对指针初始化initializer_list<int>
实例(第一个元素和一个超过结束的指针) element)或指针和长度(libstdc ++和libc ++似乎都是这样做的。)
创建实例后,您的代码可以访问概要中列出的所有成员函数。
库是否需要私有构造函数?编译器不能做什么?
正如libstdc ++私有构造函数定义上面的注释所暗示的那样,编译器能够发出绕过正常访问控制的代码,所以不,我会说拥有那个构造函数并不重要。编译器可以使用默认构造函数构造一个空的initializer_list
实例,然后为私有数据成员分配适当的值(这些成员也没有在概要中列出,但是是必要的。)
但是当私有构造函数提供编译器可以调用的干净接口时,为什么还要烦恼呢?
答案 1 :(得分:1)
问题归结为一个实现是否可以定义超出标准规定的内容。是的,这是可能的。
确实§17.6.5.5(草案编号3797)声明:
对C ++标准中描述的成员函数签名的调用 库的行为就像实现声明没有其他成员一样 功能签名。
脚注189:
189)有效的C ++程序总是调用预期的库成员 功能,或具有同等行为的功能。实施可能 还定义了其他不属于的成员函数 由有效的C ++程序调用。
即使可以访问这些附加成员函数,也不允许您调用这些函数。
std::initializer_list
库是否需要私有构造函数?编译器不能做什么?
标准定义了从初始化列表构建std::initializer_list<T>
时所期望的内容。它的完成方式是实现定义的,如上所述,它可能因此调用private
构造函数。