是否为initializer_list提供了一个私有构造函数?

时间:2015-03-22 21:24:10

标签: c++ c++11 language-lawyer c++-standard-library

该标准草案显示了initializer_list的概要。它没有私人构造函数。

http://i.stack.imgur.com/5bc61.png

但是我看过的两个标准库实现,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>对象   参考那个数组。

所以我的问题是:

  • 概要不明确吗?

  • 库是否需要私有构造函数?编译器不能做什么?

2 个答案:

答案 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构造函数。