Подтвердить что ты не робот

Error: анахроничный инициализатор базового класса старого стиля

Следующий код создает следующую ошибку компиляции для всех версий GCC, которые я пробовал, в режимах С++ 98, С++ 11 и С++ 14:

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 ссылки Я нашел к этому в Интернете были люди, которые сталкивались с ошибкой, когда имя участника было случайно выведено макросом, что в итоге привело к тому же самому коде, что и выше:

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

Эти люди никогда не узнали, что такое ошибка, хотя позже они по крайней мере обнаружили, почему их программа была нарушена.

4b9b3361

Ответ 1

Найден в документации для выпуска CFSS 1984-5, первого компилятора С++:

Конструктор можно записать так:

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

Конструкция: (hb-lb + 1) используется для указания списка аргументов, необходимых для вектора конструктора базового класса().

Имеет смысл, если вы думаете об этом. Предположительно, явное назначение имени базового класса было добавлено для поддержки множественного наследования.

Подтвердите http://www.softwarepreservation.org/projects/c_plus_plus/ для архивирования документов.

... и ничего себе, я только сейчас понял, что "CFront" - это игра слов.

Ответ 2

Действительно, это недопустимый стандарт С++, поэтому мы должны посмотреть на анналы истории языков, чтобы найти точку, в которой это стало недействительным.

В 1989 году, когда дальнейшее определение "С++" с момента его первоначального создания под этим именем в 1985 году, Stroustrup объявил, что базовая инициализация изменилась с языка предыдущих воплощений, чтобы справиться с множественным наследованием: [1]

[p191] Язык программирования С++ [Stroustrup 1986] описывает С++, как он определен и реализован в августе 1985 года. В этой статье описывается рост языка с тех пор и уточняется несколько моментов в определении. Подчеркивается, что эти языковые модификации являются расширениями; С++ был и останется стабильным языком, подходящим для долгосрочного развития программного обеспечения. Основные новые возможности С++: множественное наследование, тип-безопасная связь, лучшее разрешение перегруженных функций, рекурсивное определение назначения и инициализации, лучшие возможности для пользовательского управления памятью, абстрактные классы, статический член функции, константные функции, защищенные члены, перегрузка оператора -> и указатели на члены. Эти функции представлены в версии 2.0 на С++.

[p214] Синтаксис инициализации базовых классов и членов был расширен, чтобы справиться с множественным наследованием и порядком инициализации была более точно определена. [..]

В этом тексте демонстрируется синтаксис инициализации базового класса, с которым мы в настоящее время знакомы, и, как уже указывал Sneftel (избавив меня от проблем с поиском более старых документов!), этого не произошло еще в 1985 году, в оригинальной реализации С++, которая сама эволюционировала из "C с классами". Итак, мы можем заключить, что С++ 2.0 представил более знакомый синтаксис в 1989 году, и эта "анахроничная" версия была действительна до тех пор.

Обратите внимание, конечно, что в вопросительном коде нет базы. Таким образом, даже в С++ 1.0 программа, в конечном счете, не была бы успешно скомпилирована. Однако мы обнаружили, почему синтаксис разбирается таким образом.

Замечательно, что GCC диагностирует неясный, давно забытый синтаксис, который не был действителен ни в одном воплощении С++ почти тридцать лет.


[1] "Эволюция С++: с 1985 по 1989 год", Bjarne Stroustrup, AT & T Bell Laboratories 1989; pdf

Ответ 3

Это было описано специально в ARM, раздел 18.3.2, как анахронизм.

Причиной таких функций было, как правило, обеспечение непрерывности для более старых версий С++ или C с классами. Все "анахронизмы" имели нежелательные характеристики. Компиляторы не обязаны предоставлять такие функции, но, если они это сделали, были обязаны разрешить программисту деактивировать его и/или быть предупреждены об использовании его.