C ++ 0x,编译器挂钩和硬编码语言功能

时间:2009-12-07 02:35:05

标签: c++ c++11 compiler-construction initializer-list

我对C ++ 0x的一些新功能有点好奇。特别是range-based for loopsinitializer lists。这两个功能都需要用户定义的类才能正常运行。

我来到this post,虽然最佳答案很有帮助。我不知道它是否完全正确(我可能只是完全误解,见第一个答案的第3条评论)。根据初始化列表的current specifications,标题定义了一种类型:

template<class E> class initializer_list {
public:
    initializer_list();

    size_t size() const; // number of elements
    const E* begin() const; // first element
    const E* end() const; // one past the last element
};

您可以在规范中看到这一点,只需按Ctrl + F 'class initializer_list'

为了将= {1,2,3}隐式地转换为initializer_list类,编译器必须了解{}initializer_list之间的关系。没有构造函数接收任何东西,所以我可以告诉initializer_list是一个包装器,它被绑定到编译器实际生成的任何东西。

for( : )循环相同,这也需要用户定义的类型才能工作(尽管根据规范,更新后不需要任何代码用于数组和初始化程序列表。但初始化程序列表需要{{ 1}},因此它是代理的用户定义代码要求。

我是否完全误解了这是如何运作的?我认为这些新功能在很大程度上依赖于用户代码,我并没有错。感觉好像功能是半生不熟的,而不是将整个功能构建到编译器中,而是由编译器完成一半,在包含中完成一半。这是什么原因?

编辑:我输入'严重依赖编译器代码',而不是'严重依赖用户代码'。我认为这完全抛弃了我的问题。我的困惑不在于编译器内置的新功能,而是编译器内置的依赖用户代码的东西。

2 个答案:

答案 0 :(得分:3)

  

我认为这些新功能在很大程度上依赖于编译器代码

并没有错

他们非常依赖编译器。无论您是否需要包含标头,事实是在这两种情况下,语法都是今天编译器的解析错误。 for (:)不太适合今天的标准,其中唯一允许的构造是for(;;)

  

感觉就好像功能是半生不熟的,而不是将整个功能构建到编译器中,而是由编译器完成一半,在包含中完成一半。这是什么原因?

必须在编译器中实现支持,但是您需要包含系统的标头才能使用它。这可以用于几个目的,在初始化列表的情况下,它将类型(编译器支持的接口)带入用户的范围,以便您可以使用它(想想如何在C中使用va_args)。在基于范围的for(只是语法糖)的情况下,你需要将Range带入范围,以便编译器可以执行它的魔力。请注意,标准将for ( for-range-declaration : expression ) statement定义为草稿中的[[6.5.4] / 1):

{ 
   auto && __range = ( expression ); 
   for ( auto __begin = std::Range<_RangeT>::begin(__range), 
         __end = std::Range<_RangeT>::end(__range); 
         __begin != __end; 
         ++__begin ) { 
      for-range-declaration = *__begin; 
      statement 
   } 
} 

如果你只想在没有Range概念的情况下实现的数组和STL容器上使用它(不是在C ++ 0x意义上),但是如果你想将语法扩展到用户定义的类中(您自己的容器)编译器可以轻松地依赖于现有的Range模板(具有您自己的专业化)。依赖于定义的模板的机制等同于在容器上需要静态接口。

大多数其他语言都朝着需要常规接口(比如容器,...)并使用运行时多态性的方向发展。如果要在C ++中完成,整个STL将不得不经历一次重大的重构,因为STL容器不共享公共基础或接口,并且它们不准备被用于polimorphically。

如果有的话,当前的标准在出局时不会被烘焙

答案 1 :(得分:1)

这只是语法糖。编译器会将给定的语法结构扩展为直接引用标准类型/符号名称的等效C ++表达式。

这不是现代C ++编译器在他们的语言和“外部世界”之间唯一的强耦合。例如,extern "C"是一种语言黑客,可以容纳C的链接模型。面向语言的声明线程局部存储的方式隐含地依赖于大量的RTL hackery来工作。

或者看看C.如何访问通过...传递的参数?你需要依赖标准库;但是它使用的魔法很难依赖C编译器如何布置堆栈帧。

<强>更新

如果有的话,C ++在这里采用的方法更多的是在C ++的精神而不是替代方案 - 这将是添加内在集合或范围类型,烘焙到语言中。相反,它是通过供应商定义的范围类型完成的。我真的不认为它与可变参数有很大的不同,如果没有供应商定义的访问器宏,它们同样没用。