class A {
public:
A(){}
};
int main() {
class::A* a = new class::A();
return 0;
}
Приведенный выше код прошел компиляцию, кажется, что class:: не имеет смысла, и мне интересно, почему class::A разрешено в C++?
Есть ли для этого какая-то причина?
@Rogue Компилирует для меня в gcc 14.2: godbolt.org/z/cnsWbP138
gcc, clang и MSVC принимают его: godbolt.org/z/zhTjPGGKG.
@Dai @wohlstad Я не предполагал, что это правильный C++, полагаю, это похоже на struct X foo. В любом случае я спросил, например, о том, чтобы не включать предупреждения и не знать, на каком компиляторе они были (на случай, если он недействителен).
Он не анализируется как *"class::" , это "class ::A"
пробелы сбивают с толку, лучше удалить их все :D
@463035818_is_not_an_ai Наоборот...
Дубликат отвечает только на половину вопроса, часть ключевого слова class.





Скучный ответ: потому что грамматика C++ это позволяет.
https://eel.is/c++draft/expr.new#nt:new-expression
new-expression:
::_opt new new-placement_opt new-type-id new-initializer_opt
...
new-type-idв свою очередь содержит type-specifier-seq, который содержит type-specifier, который содержит simple-type-specifier, который позволяет elaborated-type-specifier, который содержит/разрешает class-key, который может быть class. elaborated-type-specifier также необязательно содержит nested-name-specifier, который может быть ::.
Это даже необходимо для устранения неоднозначности, как в этом Демо с (злом) A A;.
Синтаксис classId представляет собой тщательно продуманный спецификатор типа. При сопоставлении идентификатора учитываются только типы классов.
Синтаксис ::Id — это квалифицированный идентификатор. Он ищет Id только в глобальном пространстве имен.
Комбинация этих двух означает, что мы ищем тип класса в глобальном пространстве имен с именем A. Это находит A, поэтому ваш пример компилируется.
Он не нашел int A; и не нашел namespace foo { class A{}; } даже внутри функции, определенной в namespace foo. Примеры
Прежде всего, мы можем отметить, что ::A* a = new ::A(); компилируется так же хорошо, ключевое слово class (или struct и т. д.) не является обязательным при объявлении объекта. Так было всегда, и я подозреваю, что причиной была совместимость с C.
:: — оператор разрешения области. Его можно использовать без левого операнда, и в этом случае он относится к глобальной области видимости. И поскольку A было объявлено в этой области, ::A работает. И мы можем заключить, что A* a = new A(); без какого-либо упомянутого пространства имен тоже компилируется нормально.
Теперь, что не скомпилируется, так это если мы сделаем это:
namespace stuff {
class A {
public:
A(){}
};
}
int main() {
::A* a = new ::A();
return 0;
}
Потому что A находится не в глобальном пространстве имен, а в stuff. Так что stuff::A* a = new stuff::A(); было бы правильно.
Теперь мы также можем отметить, что stuff class::A — это тарабарщина и неверный синтаксис. Но class stuff::A можно было бы.
Я подозреваю, что причиной была совместимость с C. Своего рода. Например, в POSIX есть struct stat и int stat(char const*, struct stat*). Поскольку у них одинаковые имена, тип stat необходимо дополнить с помощью struct stat или class stat, чтобы устранить неоднозначность с помощью функции int stat(). C требует уточнения struct, если только нет помощника typedef struct stat stat_t; (здесь с другим именем, чтобы избежать конфликта с функцией).
@Eljay Правильным решением, конечно, было бы дать ему осмысленное имя. Есть правильные методы программирования, а есть POSIX...
Никаких аргументов с моей стороны. Мне трудно отличить C от валлийского.
Какую команду вы использовали для компиляции?