Конфликтующие объявления
Если не указано иное, два объявления не могут повторно вводить одну и ту же сущность. Если такие объявления существуют, программа некорректна.
Соответствующие объявления
Два объявления соответствуют, если они повторно вводят одно и то же имя, оба объявляют конструкторы или оба объявляют деструкторы, за исключением случаев, когда
- одно из них является using объявлением,
- одно объявляет тип (не имя typedef), а другое объявляет переменную, нестатический член данных, не являющийся членом анонимного объединения, перечислитель, функцию или шаблон функции, либо
- каждое объявляет функцию или шаблон функции, и они не объявляют соответствующие перегрузки.
Соответствующие перегрузки функций
Два объявления функций объявляют соответствующие перегрузки, если оба объявляют функции, удовлетворяющие всем следующим условиям:
- У них одинаковый список типов параметров, без учета типов явных параметров объекта(начиная с C++23).
| (начиная с C++20) |
- Если обе они являются нестатическими функциями-членами, они должны дополнительно удовлетворять одному из следующих требований:
| (начиная с C++23) |
- Их параметры объекта имеют одинаковый тип.
Соответствующие перегрузки шаблонов функций
Два объявления шаблонов функций объявляют соответствующие перегрузки, если оба объявляют шаблоны функций, удовлетворяющие всем следующим условиям:
- Списки параметров шаблона имеют одинаковую длину.
- Соответствующие параметры шаблона эквивалентны.
- У них эквивалентные списки типов параметров, без учета типов явных параметров объекта(начиная с C++23).
- У них эквивалентные типы возвращаемых значений.
| (начиная с C++20) |
- Если обе они являются шаблонами нестатических функций-членов, они должны дополнительно удовлетворять одному из следующих требований:
| (начиная с C++23) |
- Их параметры объекта имеют эквивалентные типы.
struct A
{
friend void c(); // #1
};
struct B
{
friend void c() {} // corresponds to, and defines, #1
};
typedef int Int;
enum E : int { a };
void f(int); // #2
void f(Int) {} // defines #2
void f(E) {} // OK, another overload
struct X
{
static void f();
void f() const; // error: redeclaration
void g();
void g() const; // OK
void g() &; // error: redeclaration
void h(this X&, int);
void h(int) &&; // OK, another overload
void j(this const X&);
void j() const &; // error: redeclaration
void k();
void k(this X&); // error: redeclaration
};
Несколько объявлений одной и той же сущности
| Объявление является независимым от имени, если его имя —
| (начиная с C++26) |
Если не указано иное, два объявления сущностей объявляют одну и ту же сущность, если выполнены все следующие условия; при этом считается, что объявления безымянных типов вводят их имена typedef и имена перечислений для целей связывания (если таковые имеются):
- Они соответствуют.
- У них одинаковая целевая область видимости, которая не является областью видимости параметров функции или областью видимости параметров шаблона.
| (начиная с 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шаблоном функции с эквивалентными списком параметров шаблона и типом.
| (начиная с C++11) |
| (начиная с C++14) |
| (начиная с C++20) |
Типы сравниваются после всех корректировок типов (в ходе которых typedef-ы заменяются их определениями). В объявлениях объекта-массива могут указываться типы массива, различающиеся наличием или отсутствием верхней границы массива. Диагностика не требуется, если ни одно объявление не достижимо из другого.
void g(); // #1
void g(int); // OK, different entity from #1 (they do not correspond)
int g(); // Error: same entity as #1 with different type
void h(); // #2
namespace h {} // Error: same entity as #2, but not a function
Если объявление H, объявляющее имя с внутренним связыванием, предшествует объявлению D в другой единице трансляции U и объявляло бы ту же сущность, что и D, если бы оно находилось в U, программа некорректна.
Потенциально конфликтующие объявления
Два объявления потенциально конфликтуют, если они соответствуют, но объявляют разные сущности.
Если в какой-либо области видимости имя связано с двумя объявлениями A и B, которые потенциально конфликтуют, B не является независимым от имени(начиная с C++26), и A предшествует B, программа некорректна:
void f()
{
int x, y;
void x(); // Error: different entity for x
int y; // Error: redefinition
}
enum { f }; // Error: different entity for ::f
namespace A {}
namespace B = A;
namespace B = A; // OK, no effect
namespace B = B; // OK, no effect
namespace A = B; // OK, no effect
namespace B {} // Error: different entity for B
void g()
{
int _;
_ = 0; // OK
int _; // OK since C++26, name-independent declaration
_ = 0; // Error: two non-function declarations in the lookup set
}
void h ()
{
int _; // #1
_ ++; // OK
static int _; // Error: conflicts with #1 because
// static variables are not name-independent
}
Отчеты об ошибках
Следующие отчеты об ошибках, изменяющие поведение, были применены задним числом к ранее опубликованным стандартам C++.
| DR | Применен к | Поведение согласно опубликованному стандарту | Корректное поведение |
|---|---|---|---|
|
CWG 279 (P1787R6) | C++98 | было неясно, можно ли повторно объявить безымянный класс или перечисление, если для целей связывания у него есть имя typedef | его можно повторно объявить |
|
CWG 338 (P1787R6) | C++98 | было неясно, можно ли повторно объявить безымянное перечисление, если для целей связывания у него есть перечислитель в качестве имени | его можно повторно объявить |
|
CWG 1884 (P1787R6) | C++98 | ограничения, применяемые к нескольким объявлениям одной и той же сущности, были неясны | разъяснено |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/conflicting_declarations