错误:不合时宜的旧式基类初始化程序

问题描述 投票:49回答:3

以下代码在C ++ 98,C ++ 11和C ++ 14模式下对我尝试的所有GCC版本产生后续编译错误:

struct T
{
    T(void* x) : (x) {}
};

// main.cpp: In constructor 'T::T(void*)':
// main.cpp:3:18: error: anachronistic old-style base class initializer [-fpermissive]
//      T(void* x) : (x) {}
//                   ^
// main.cpp:3:16: error: unnamed initializer for 'T', which has no base classes
//      T(void* x) : (x) {}

当然,它显然是破碎的代码,因为我实际上并没有初始化任何东西。

但为什么它是基类初始化器,为什么它是“不合时宜的”,而不是简单的错误?曾经有效吗?什么时候?这是什么意思?


我在网上找到的only related references一直是人们遇到错误,当一个成员名称被意外地宏出时,实际上产生了与上面相同的代码:

#define bar
// ^ some library could have done this

struct T
{
    T(int x)
        : bar(x)   // effectively just `: (x)`
    {}

    int bar;       // will cause its own error
};

那些人从来没有找到错误的含义,尽管他们后来至少发现了为什么他们的程序被打破了。

c++ c++11 gcc c++14 c++03
3个回答
54
投票

在第一个C ++编译器的CCront 1984-5版本的文档中找到:

构造函数可以这样写:

  vec.vec(int lb, int hb) : (hb-lb+1)
  {
      if (hb-lb<0) hb = lb;
      low = lb;
      high = hb; 
  }

构造:(hb-lb + 1)用于指定基类构造函数vector()所需的参数列表。

如果你考虑的话,这是有道理的。据推测,添加了基类的显式命名以支持多重继承。

感谢http://www.softwarepreservation.org/projects/c_plus_plus/存档文件。

......哇,我刚刚意识到“面对面”是一个文字游戏。


23
投票

实际上,这不是有效的标准C ++,因此我们必须查看语言历史的历史,以找到它变得无效的点。

1989年,当自1985年以该名称开始进一步定义“C ++”时,Stroustrup宣称基础初始化已从语言的先前化身改变,以应对多重继承:[1]

[p191] C ++编程语言[Stroustrup 1986]描述了1985年8月定义和实现的C ++。本文描述了从那时起语言的发展,并阐明了定义中的几点。强调这些语言修改是扩展; C ++已经并将继续是一种适合长期软件开发的稳定语言。 C ++的主要新特性是:多重继承,类型安全链接,更好的重载函数解析,赋值和初始化的递归定义,更好的用户定义内存管理工具,抽象类,静态成员函数,const成员函数,受保护成员,运算符->的重载,以及指向成员的指针。这些功能在C ++的2.0版本中提供。

[p214]初始化基类和成员的语法已经扩展到应对多重继承,并且已经更精确地定义了初始化的顺序。 [..]

本文接着演示了我们目前熟悉的基类初始化语法,正如Sneftel已经指出的那样(省去了通过任何更旧的文档进行搜索的麻烦!),这种情况并非如此。 1985年,在原始的C ++实现中,它本身是从“C with Classes”演变而来的。因此,我们可以得出结论,C ++ 2.0在1989年引入了更为熟悉的语法,这个“不合时宜”的版本在此之前是有效的。

当然,请注意,在问题的代码中,没有基础。因此,即使在C ++ 1.0中,该程序最终也不会成功编译。但是,我们已经发现了为什么以这种方式解析语法。

值得注意的是,GCC正在诊断模糊不清,长期被遗忘的语法,这种语法在C ++的任何版本中都有效近三十年。


[1]“C ++的演变:1985年至1989年”,Bjarne Stroustrup,AT&T贝尔实验室1989; pdf


6
投票

这在ARM,第18.3.2节中具体描述为不合时宜的。

这些功能的原因通常是为旧版本的C ++或带有类的C提供连续性。所有“时代错误”都具有不良特征。编译器不需要提供这些功能,但如果他们这样做,则必须允许程序员停用它和/或被警告使用它。

© www.soinside.com 2019 - 2024. All rights reserved.