Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

error: anachronistic old-style base class initializer

The following code produces the subsequent compilation error on all versions of GCC that I've tried, in C++98, C++11 and C++14 modes:

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

Sure, it's clearly broken code because I'm not actually initialising anything.

But why is it a base-class initialiser and why is it "anachronistic", rather than simply wrong? Was it once valid? When? And what did it mean?


The only related references I've found to this on the web have been people coming across the error when a member name was accidentally macro'd out, effectively resulting in the same code as above:

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

Those people never did find out what the error meant, although they later at least discovered why their program was broken.

like image 479
Lightness Races in Orbit Avatar asked Apr 02 '15 20:04

Lightness Races in Orbit


3 Answers

Found in the documentation for the 1984-5 release of CFront, the first C++ compiler:

The constructor can be written like this:

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

The construct : (hb-lb+1) is used to specify the argument list needed for the base class constructor vector().

Makes sense, if you think about it. Presumably the explicit naming of the base class was added to support multiple inheritance. (At the time there was no support for member initializer lists -- members were unconditionally default-constructed -- so before multiple inheritance there was exactly one thing a constructor could initialize there.)

Credit to http://www.softwarepreservation.org/projects/c_plus_plus/ for archiving the documents.

...and wow, I just now realized that "CFront" was a play on words.

like image 102
Sneftel Avatar answered Nov 20 '22 14:11

Sneftel


Indeed this is not valid standard C++, so we must look to the annals of the language's history to find the point at which this became invalid.

In 1989, when further defining "C++" since its original inception under that name in 1985, Stroustrup declared that base initialisation had changed from the language's previous incarnations, in order to cope with multiple inheritance: [1]

[p191] The C++ Programming Language [Stroustrup 1986] describes C++ as defined and implemented in August 1985. This paper describes the growth of the language since then and clarifies a few points in the definition. It is emphasized that these language modifications are extensions; C++ has been and will remain a stable language suitable for long term software development. The main new features of C++ are: multiple inheritance, type-safe linkage, better resolution of overloaded functions, recursive definition of assignment and initialization, better facilities for user-defined memory management, abstract classes, static member functions, const member functions, protected members, overloading of operator ->, and pointers to members. These features are provided in the 2.0 release of C++.

[p214] The syntax for initializing base classes and members has been extended to cope with multiple inheritance and the order of initialization has been more precisely defined. [..]

The text goes on to demonstrate the base-class initialisation syntax with which we are presently familiar and, as Sneftel has already pointed out (saving me the trouble of hunting through any more old documents!), this had not been the case as late as 1985, in the original C++ implementation that itself evolved out of "C with Classes". So, we can conclude that C++ 2.0 introduced the more familiar syntax in 1989 and this "anachronistic" version was valid until then.

Note, of course, that in the question's code, there is no base. So, even in C++ 1.0, the program would ultimately not have successfully compiled. However, we have discovered why the syntax is being parsed in such a way.

It's remarkable that GCC is diagnosing obscure, long-forgotten syntax that has not been valid in any incarnation of C++ for almost thirty years.


[1] "The Evolution of C++: 1985 to 1989", Bjarne Stroustrup, AT&T Bell Laboratories 1989; pdf

like image 24
Lightness Races in Orbit Avatar answered Nov 20 '22 14:11

Lightness Races in Orbit


This was described specifically in the ARM, Section 18.3.2 as an anachronism.

The reason for such features was, typically, providing continuity to older versions of C++ or to C with classes. All "anachronisms" had undesirable characteristics. Compilers were not required to provide such features but, if they did, were obliged to permit a programmer to deactivate it and/or be warned about using it.

like image 6
Peter Avatar answered Nov 20 '22 14:11

Peter