5

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

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

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( : ),它也需要用户定义的类型才能工作(尽管根据规范,更新为不需要数组和初始化列表的任何代码。但初始化列表需要<initializer_list>,所以这是用户定义的代码要求代理)。

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

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

4

2 回答 2

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 
   } 
} 

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

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

如果有的话,当前的标准在它淘汰时不会被低估。

于 2009-12-07T07:46:55.400 回答
1

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

这不是现代 C++ 编译器在其语言和“外部世界”之间唯一的强耦合。例如,extern "C"为了适应 C 的链接模型,这是一种语言技巧。声明线程本地存储的面向语言的方式隐式依赖于大量 RTL 黑客技术的工作。

或者看看 C。你如何访问通过传递的参数...?你需要依赖标准库;但这使用的魔法非常依赖于 C 编译器如何精确地布置堆栈帧。

更新:

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

于 2009-12-07T03:32:13.240 回答