为什么std :: initializer_list不是内置的语言?

时间:2013-03-04 09:58:52

标签: c++ c++11 std initializer-list

为什么std::initializer_list内核不是核心语言?

在我看来,它是C ++ 11的一个非常重要的功能,但它没有自己的保留关键字(或类似的东西)。

相反,initializer_list它只是 来自标准库的模板类,它具有来自新 braced-init-的特殊的,隐式映射列出由编译器处理的 {...}语法。

首先想到的是,这个解决方案非常 hacky

这是现在实现C ++语言新增功能的方式:某些模板类的隐式角色而不是核心语言?


请考虑以下示例:

   widget<int> w = {1,2,3}; //this is how we want to use a class

为什么选择了新课程:

   widget( std::initializer_list<T> init )

而不是使用类似来解决这些问题:

   widget( T[] init, int length )  // (1)
   widget( T... init )             // (2)
   widget( std::vector<T> init )   // (3)
  1. 一个经典数组,你可以在这里和那里添加const
  2. 语言中已存在三个点(var-args,现在是可变参数模板),为什么不重复使用语法(并使其感觉内置
  3. 只是一个现有容器,可以添加const&
  4. 所有这些都已成为该语言的一部分。我只写了我的第一个想法,我确信还有很多其他方法。

6 个答案:

答案 0 :(得分:47)

已经有“核心”语言功能的示例返回std命名空间中定义的类型。 typeid会返回std::type_info并且(或许延伸一点)sizeof会返回std::size_t

在前一种情况下,您需要包含一个标准标题才能使用这种所谓的“核心语言”功能。

现在,对于初始化列表,发生生成对象时不需要关键字,语法是上下文相关的花括号。除此之外,它与type_info相同。就个人而言,我认为没有关键字会让它“更加黑客”。或许更令人惊讶,但请记住,目标是允许聚合已经允许的相同的braced-initializer语法。

所以是的,您可能会在未来期待更多这种设计原则:

  • 如果出现更多可能在没有新关键字的情况下引入新功能的情况,那么委员会将接受它们。
  • 如果新功能需要复杂类型,那么这些类型将放在std而不是内置。

因此:

  • 如果新功能需要复杂类型并且可以在没有新关键字的情况下引入,那么您将获得此处所拥有的内容,这是“核心语言”语法,没有新关键字,并且使用来自std的库类型

我认为,在“核心语言”和标准库之间,C ++中没有绝对的划分。它们是标准中的不同章节,但每个都引用另一个章节,而且一直如此。

C ++ 11中还有另一种方法,即lambdas引入了具有由编译器生成的匿名类型的对象。因为它们没有名称,所以根本不在命名空间中,当然不在std中。但是,这不适合初始化程序列表,因为在编写接受它的构造函数时使用类型名称。

答案 1 :(得分:42)

C ++标准委员会似乎不想添加新的关键字,可能是因为这增加了破坏现有代码的风险(遗留代码可以使用该关键字作为变量,类或其他任何名称)。

此外,在我看来,将std::initializer_list定义为模板化容器是一个非常优雅的选择:如果它是关键字,您将如何访问其基础类型?你会如何迭代它?你也需要一堆新的操作符,这只会迫使你记住更多的名字和更多的关键词来做与标准容器相同的事情。

std::initializer_list视为任何其他容器,您可以编写适用于任何其他容器的通用代码。

<强>更新

  

那么为什么要引入新类型,而不是使用现有的某种组合? (来自评论)

首先,所有其他容器都有添加,删除和放置元素的方法,这些方法对于编译器生成的集合来说是不可取的。唯一的例外是std::array<>,它包装了一个固定大小的C风格数组,因此仍然是唯一合理的候选者。

但是,正如Nicol Bolas在评论中正确指出的那样,std::initializer_list与所有其他标准容器(包括std::array<>)之间的另一个根本区别在于后者具有值语义,而std::initializer_list具有引用语义。例如,复制std::initializer_list不会导致它包含的元素的副本。

此外(再一次,由Nicol Bolas提供),拥有一个特殊的大括号初始化容器容器允许在用户执行初始化的方式上进行重载。

答案 2 :(得分:6)

这不是什么新鲜事。例如,for (i : some_container)依赖于some_container类中的existence of specific methods or standalone functions。 C#甚至更依赖于它的.NET库。实际上,我认为,这是一个非常优雅的解决方案,因为您可以使您的类与某些语言结构兼容,而不会使语言规范复杂化。

答案 3 :(得分:4)

这确实不是什么新鲜事,有多少人指出,这种做法存在于C ++中,例如,在C#中。

Andrei Alexandrescu已经提到了一个很好的观点:你可能会认为它是想象中的“核心”命名空间的一部分,然后它会更有意义。

所以,它实际上类似于:core::initializer_listcore::size_tcore::begin()core::end()等等。这只是一个不幸的巧合,std命名空间里面有一些核心语言结构。

答案 4 :(得分:2)

它不仅可以在标准库中完全运行。包含在标准库中并不意味着编译器不能发挥巧妙的技巧。

虽然它可能无法在所有情况下,但它可能很好地说:这种类型是众所周知的,或者是一种简单的类型,让我们忽略initializer_list并且只有一个内存图像的初始化值应该是。

换句话说,int i {5};可以等同于int i(5);int i=5;甚至intwrapper iw {5};其中intwrapper是一个简单的包装类而不是一个简单的int构造函数采用initializer_list

答案 5 :(得分:1)

它不是核心语言的一部分,因为它可以完全在库中实现,只需要行operator newoperator delete。使编译器构建起来更加复杂有什么优势呢?