Conflicting declarations
Если не указано иное, два объявления не могут (пере)вводить одну и ту же сущность. Программа является некорректной, если такие объявления существуют.
Содержание |
Соответствующие объявления
Две декларации соответствуют друг другу, если они (повторно) вводят одно и то же имя, обе объявляют конструкторы или обе объявляют деструкторы, за исключением случаев, когда
- либо это using declaration ,
- один объявляет тип (не typedef name ), а другой объявляет переменную, нестатический член данных, отличный от anonymous union , перечислитель, функцию или шаблон функции, или
- каждый объявляет функцию или шаблон функции и они не объявляют соответствующие перегрузки.
Соответствующие перегрузки функций
Два объявления функций объявляют соответствующие перегрузки если оба объявляют функции, удовлетворяющие всем следующим условиям:
- Они имеют одинаковый parameter-type-list , за исключением типов explicit object parameters (since C++23) .
|
(since C++20) |
- Если оба из них являются нестатическими функциями-членами, они должны дополнительно удовлетворять одному из следующих требований:
|
(since C++23) |
-
- Их объектные параметры имеют одинаковый тип.
Соответствующие перегрузки шаблонов функций
Два объявления шаблонов функций объявляют соответствующие перегрузки если оба объявляют шаблоны функций, удовлетворяющие всем следующим условиям:
- Их списки параметров шаблонов имеют одинаковую длину.
- Их соответствующие параметры шаблонов эквивалентны .
- Они имеют эквивалентные списки типов параметров , исключая типы явных параметров объекта (начиная с C++23) .
- Они имеют эквивалентные типы возвращаемых значений.
|
(since C++20) |
- Если оба являются шаблонами функций-членов, не являющихся статическими, они должны дополнительно удовлетворять одному из следующих требований:
|
(начиная с C++23) |
-
- Их объектные параметры имеют эквивалентные типы.
struct A { friend void c(); // #1 }; struct B { friend void c() {} // соответствует и определяет #1 }; typedef int Int; enum E : int { a }; void f(int); // #2 void f(Int) {} // определяет #2 void f(E) {} // OK, другая перегрузка struct X { static void f(); void f() const; // ошибка: повторное объявление void g(); void g() const; // OK void g() &; // ошибка: повторное объявление void h(this X&, int); void h(int) &&; // OK, другая перегрузка void j(this const X&); void j() const &; // ошибка: повторное объявление void k(); void k(this X&); // ошибка: повторное объявление };
Множественные объявления одной и той же сущности
|
Объявление является не зависящим от имени , если его имя - _ и оно объявляет
|
(начиная с C++26) |
Если не указано иное, два объявления сущностей объявляют одну и ту же сущность при выполнении всех следующих условий, с учетом того, что объявления безымянных типов вводят их typedef имена и имена перечислений для целей линковки (если таковые существуют):
- Они соответствуют.
- Они имеют одинаковую область видимости цели , которая не является областью видимости параметров функции или областью видимости параметров шаблона .
|
(since C++26) |
- Выполняется одно из следующих условий:
-
- Они появляются в той же единице трансляции.
|
(начиная с C++20) |
-
- Они оба объявляют имена с внешней линковкой .
Объявление сущности или имени typedef
X
является
повторным объявлением
для
X
, если из него достижимо другое объявление
X
; в противном случае это
первое объявление
для
X
.
Ограничения
Если любые два объявления сущности
E
нарушают соответствующее ограничение ниже, программа является некорректной:
-
Если один объявляет
Eкак переменную, другой также должен объявитьEкак переменную того же типа. -
Если один объявляет
Eкак функцию , другой также должен объявитьEкак функцию того же типа. -
Если один объявляет
Eкак перечислитель , другой также должен объявитьEкак перечислитель. -
Если один объявляет
Eкак пространство имён , другой также должен объявитьEкак пространство имён. -
Если один объявляет
Eкак классовый тип , другой также должен объявитьEкак классовый тип. -
Если один объявляет
Eкак тип перечисления , другой также должен объявитьEкак тип перечисления. -
Если один объявляет
Eкак шаблон класса , другой также должен объявитьEкак шаблон класса с эквивалентным списком параметров шаблона (см. перегрузка шаблонов функций ). -
Если один объявляет
Eкак шаблон функции , другой также должен объявитьEкак шаблон функции с эквивалентным списком параметров шаблона и типом.
|
(since C++11) |
|
(since C++14) |
|
(since C++20) |
Типы сравниваются после всех корректировок типов (в процессе которых typedefs заменяются своими определениями). Объявления для массива могут указывать типы массивов, отличающиеся наличием или отсутствием основного размера массива. Диагностическое сообщение не требуется, если ни одно объявление не достижимо из другого.
void g(); // #1 void g(int); // OK, другая сущность от #1 (они не соответствуют) int g(); // Ошибка: та же сущность, что и #1, но с другим типом void h(); // #2 namespace h {} // Ошибка: та же сущность, что и #2, но не функция
Если объявление
H
, которое объявляет имя с
внутренней линковкой
, предшествует объявлению
D
в другой единице трансляции
U
и объявляло бы ту же сущность, что и
D
, если бы оно находилось в
U
, программа является некорректной.
Потенциально конфликтующие объявления
Два объявления потенциально конфликтуют если они соответствуют, но объявляют разные сущности.
Если в любой области видимости имя связано с двумя объявлениями
A
и
B
, которые потенциально конфликтуют
,
B
не является name-independent
(since C++26)
, и
A
предшествует
B
, программа является некорректной:
void f() { int x, y; void x(); // Ошибка: другая сущность для x int y; // Ошибка: переопределение } enum { f }; // Ошибка: другая сущность для ::f namespace A {} namespace B = A; namespace B = A; // OK, без эффекта namespace B = B; // OK, без эффекта namespace A = B; // OK, без эффекта namespace B {} // Ошибка: другая сущность для B void g() { int _; _ = 0; // OK int _; // OK начиная с C++26, независимое от имени объявление _ = 0; // Ошибка: два нефункциональных объявления в наборе поиска } void h () { int _; // #1 _ ++; // OK static int _; // Ошибка: конфликтует с #1, потому что // статические переменные не являются независимыми от имени }
Отчеты о дефектах
Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C++.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
|
CWG 279
( P1787R6 ) |
C++98 |
было неясно, может ли неназванный класс или перечисление
быть переобъявленным, если у него есть typedef-имя для целей линковки |
может быть переобъявлен |
|
CWG 338
( P1787R6 ) |
C++98 |
было неясно, может ли неназванное перечисление быть
переобъявленным, если у него есть перечислитель в качестве имени для целей линковки |
может быть переобъявлено |
|
CWG 1884
( P1787R6 ) |
C++98 |
ограничения, применяемые к множественным
объявлениям одной и той же сущности, были неясны |
прояснены |