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

Определяет ли определение конструктора пространства имен идентификатор класса?

Здесь мы все узнали в День 1 из С++, который мы считаем само собой разумеющимся, но явно не следует из формулировки Стандарта.

Учитывая класс S, мы можем определить его конструктор

struct S { S(); };
S::S() { … }

Но стандарт, похоже, позволяет это также:

struct S { S(); };
S() { … }

Квалификация имени класса с самим собой всегда разрешена, но всегда избыточна. Например, S::S::S::S() { … } также является допустимым объявлением. Если S::S, то почему не просто S?

Из С++ 11 §12.1/1,

Конструкторы не имеют имен. Для объявления или определения конструктора используется специальный синтаксис декларатора. Синтаксис использует:

- необязательный spec-specifier-seq, в котором каждый spec-спецификатор является либо спецификатором функции, либо constexpr,

- имя класса конструкторов и

- список параметров

в этом порядке.

В равной степени это относится к области класса или пространства имен. Существует специальное правило об области пространства имен, §9.3/5,

Если определение функции-члена лексически выходит за пределы определения его класса, имя функции-члена должно быть присвоено его именем класса с помощью оператора::.

Однако конструкторы не имеют имен, поэтому это не применяется, правильно? Более того, нет причин требовать квалификации, потому что нет синтаксической двусмысленности. Функция, объявленная без возвращаемого типа и имя класса для идентификатора, всегда является синтаксической ошибкой в ​​соответствии с действующими правилами. Правильно?

Не нужно начинать писать код с опусканием квалификации, но есть ли причина, по которой компилятор не принимает этого, или это просто традиция?

4b9b3361

Ответ 1

При столкновении с токенами S() { } в области пространства имен компилятор не может магически решить это ctor. Какое грамматическое правило создавало бы такую ​​последовательность токенов? Пусть игнорируют все, кроме функциональных определений; они не могут создать часть ( ){ }.

Это означает, что S() должен быть декларатором, а decl-specifier-seq opt должен быть пустым (см. раздел 8.3.4). В §9.2/7 впоследствии говорится, что декларатор должен называть конструктор, деструктор или функцию преобразования. Но S тоже не указывается. Поэтому S() { } является недопустимым.

Ответ 2

Да, он говорит, что

Если определение функции-члена лексически вне определения класса   имя функции-члена должно быть присвоено его именем класса с помощью оператора::.

Но он не говорит, что функция-член w/o name должна быть не квалифицироваться по имени своего класса. Имеет ли это?;)

Это, по-видимому, приводит к неопределенной области в зависимости от реализаций. Однако форма A:: A определяется стандартом.

5.1 Первичные выражения

Если используется имя класса: class-name, а два имени класса относятся к одному классу, это обозначение именует конструктор..

Относительно того, разрешен ли A(){..} или нет, я полагаю, что нет причин делать это условно (есть ли какой-нибудь компилятор С++ для него? AFAIK, nope):

  • Поскольку конструктор является специальной функцией-членом, способ A::A(){..} более согласован с другими функциями-членами. Почему именно борт позволяет ему вести себя особенно? Это, вероятно, не стоит усилий.

  • Никто не хочет рисковать писать несоответствующий код, который явно не указан в стандарте.