以下代码在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 rel ated 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
};
那些人从未弄清楚错误的含义,尽管他们后来至少发现了为什么他们的程序被打破了。
答案 0 :(得分:54)
在第一个C ++编译器的第一个C ++编译器的1984-15版本的文档中找到:
构造函数可以这样写:
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/归档文件。
...哇,我刚刚意识到&#34; CFront&#34;是一个文字游戏。
答案 1 :(得分: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&amp; T贝尔实验室1989; pdf
答案 2 :(得分:6)
这在ARM第18.3.2节中具体描述为不合时宜的。
这些功能的原因通常是为旧版本的C ++或带有类的C提供连续性。所有“时代错误”都具有不良特征。编译器不需要提供这样的功能,但如果他们这样做,则必须允许程序员停用它和/或被警告使用它。