Я удивлен, что следующий простой код не будет компилироваться (с gcc, версия 4.8.1)
#include <string>
void test()
{
std::string* p = new std::string("Destruct me");
p->std::~string();
}
В нем говорится: error: scope 'std before' ~ не является именем класса. Однако, прочитав стандарт, я бы сказал, что синтаксис говорит, что это должно быть "postfix-expresssion → псевдо-конструктор-имя", где псевдоконструктор-имя может иметь форму "имя-имя-спецификатор-type-name", и вложенным именем-спецификатором может быть "идентификатор".
Оставшаяся "std::" приводит к жалобе на то, что перед левым парнем ожидалось имя класса, и после того, как тильда подала жалобу на то, что имя класса ожидалось до "::". После некоторых попыток я обнаружил, что он скомпилируется при записи p->std::string::~string();
(но не при записи p->std::string::~std::string();
). Но квалификация деструктора с собственным типом имен не является нейтральной операцией; Я собираюсь из примера в 12.4: 13 стандартного (но с любопытством не из нормативного текста), что это заставляет деструктор точного статического (базового) класса вызываться, а не как виртуальную функцию, тип) фактического объекта, на который указывает. Здесь это не имеет значения, но в подобных случаях это было бы; почему синтаксическая сила использует исключительно статический тип?
Однако с clang вместо gcc даже упомянутый вариант дает синтаксическую ошибку. Сообщения об ошибках clang более забавные, хотя, если вы настроены на такой юмор при чтении сообщений об ошибках: для p->std::string::~string();
он дает "ожидаемое имя класса после" ~ ", чтобы назвать деструктор" (и поэтому он задается вопросом: какие типы имен классов не будут называть деструктор, если префикс тильды), а для моего начального испытания p->std::~string()
он реплицирует "квалифицированный доступ к члену" относится к члену в пространстве имен "std" (снова один задается вопросом, что с этим не так, ведь деструктор, который будет называться, живет в пространстве имен "std" ). Я пробовал все 8 разумных комбинаций (std:: и/или string:: перед тильдой, и/или std:: после него), и ни одна из них не компилируется с clang.
Я могу скомпилировать его, даже с clang, используя using std::string;
. Но то, что мне кажется любопытным, заключается в том, что я не могу найти в стандарте никаких указаний о том, что такое объявление должно было быть необходимо в таких случаях. На самом деле я не могу найти ничего, что могло бы решить проблему вызова деструктора класса, Мне что-то не хватает?
В качестве заключительной заметки я хотел бы добавить, что мне кажется странным, что при вызове деструктора нужно использовать квалификацию пространства имен. Поскольку это членский доступ из хорошо определенного объекта (здесь *p
), не должен зависящий от аргумента поиск явно запрещает ненужное пространство имен?