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

Dav*_*ave 5 c++ compiler-construction initializer-list c++11

我对C++ 0x的一些新功能有点好奇.特别是基于范围的for循环初始化列表.这两个功能都需要用户定义的类才能正常运行.

我来到这篇文章,虽然最佳答案很有帮助.我不知道它是否完全正确(我可能只是完全误解,见第一个答案的第3条评论).根据初始化列表的当前规范,标头定义了一种类型:

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
};
Run Code Online (Sandbox Code Playgroud)

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

为了= {1,2,3}隐式铸造成initializer_list类,编译器有关系的一些知识{}initializer_list.没有构造函数接收任何东西,所以我可以告诉initializer_list是一个包装器,它被绑定到编译器实际生成的任何东西.

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

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

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

Dav*_*eas 3

我认为这些新功能实际上极度依赖编译器代码,这一点并没有错。

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

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

该支持必须在编译器中实现,但您需要包含系统的标头才能使其工作。这可以有几个目的,在初始化列表的情况下,它将类型(编译器支持的接口)带入用户范围,以便您可以有一种使用它的方法(想想 va_args 在 C 中的情况)。对于基于范围的 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 
   } 
} 
Run Code Online (Sandbox Code Playgroud)

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

大多数其他语言都朝着需要常规接口(例如容器,...)并在其上使用运行时多态性的方向发展。如果要在 C++ 中完成此操作,则整个 STL 必须进行重大重构,因为 STL 容器不共享公共基础或接口,并且它们不准备用于多态性。

如果有的话,当前的标准在发布时也不会变得不成熟。