Уточнение при поиске имени
-
28-09-2019 - |
Вопрос
$ 10,2 / 4- "[ Примечание:Поиск имени в детализированный спецификатор типа (3.4.4) или базовый спецификатор (пункт 10), например, игнорирует все объявления, не относящиеся к типу , при поиске имени в спецификаторе вложенного имени (3.4.3) игнорирует объявления функций, переменных и перечислителя."
Я обнаружил, что это утверждение очень сбивает с толку в этом разделе при описании поиска по имени.
void S(){}
struct S{
S(){cout << 1;}
void f(){}
static const int x = 0;
};
int main(){
struct S *p = new struct ::S; // here ::S refers to type
p->::S::f();
S::x; // base specifier, ignores the function declaration 'S'
::S(); // nested name specifier, ignores the struct declaration 'S'.
delete p;
}
Мои вопросы:
Правильно ли я понимаю правила?
Почему
::S
в строке doing new автоматически обрабатывается значение structS
, тогда как в последней строке::S
означает функцииS
в глобальном пространстве имен.Указывает ли это на двусмысленность в документации, или это еще один день для меня, чтобы держаться подальше от стандартного документа C ++?
Решение
Q1: я так думаю.
Q2: совместимость с C. Когда вы объявляете struct
В C имя тега именно то, что имя тега. Чтобы иметь возможность использовать его автономным способом, вам нужен typedef
. Отказ В C ++ вам не нужен Typedef, который облегчает проще. Но правила C ++ были осложнены необходимостью иметь возможность импортировать уже существующие заголовки C, которые «перегружены» имя тега с именем функции. Канонический пример этого является UNIX stat()
Функция, которая использует struct stat*
как аргумент.
Q3: Стандартное чтение обычно довольно сложно ... Вам нужно уже знать, что нет места в другом месте, модифицируя то, что вы читаете. Не странно, что люди, зная, как это сделать, это юрист языка ...
Другие советы
Вы ошибаетесь насчет второго комментария.В S::x
, тот самый S
является именем во вложенном спецификаторе имени.То, на что Стандарт ссылается с помощью "base-specifier", заключается в следующем
namespace B { struct X { }; void X() }
struct A : B::X { }; // B::X is a base-specifier
Вы также не правы на этот счет:
::S();
// спецификатор вложенного имени, игнорирует объявление структуры 'S'.`
Этот код вызывает функцию не потому, что ::S
был бы спецификатором вложенного имени (это не спецификатор вложенного имени!), А потому, что имена функций скрывают имена классов или перечислений, если и функция, и класс / перечисление объявлены в одной области видимости.
FWIW, следующий код был бы в равной степени действителен для строки 2 вашего основного
p->S::f();
Важно то, что S
предшествует ::
, что заставляет lookup игнорировать функцию.Что вы положили ::
до того, как S
в вашем случае это не имеет никакого эффекта.