Spec-Zone.ru › C++

Конфликтующие объявления

Если не указано иное, два объявления не могут повторно вводить одну и ту же сущность. Если такие объявления существуют, программа некорректна.

Соответствующие объявления

Два объявления соответствуют, если они повторно вводят одно и то же имя, оба объявляют конструкторы или оба объявляют деструкторы, за исключением случаев, когда

  • одно из них является using объявлением,
  • одно объявляет тип (не имя typedef), а другое объявляет переменную, нестатический член данных, не являющийся членом анонимного объединения, перечислитель, функцию или шаблон функции, либо
  • каждое объявляет функцию или шаблон функции, и они не объявляют соответствующие перегрузки.

Соответствующие перегрузки функций

Два объявления функций объявляют соответствующие перегрузки, если оба объявляют функции, удовлетворяющие всем следующим условиям:

  • У них одинаковый список типов параметров, без учета типов явных параметров объекта(начиная с C++23).
  • У них эквивалентные завершающие предложения requires (если имеются; исключение составляют объявления friend).
(начиная с C++20)
  • Если обе они являются нестатическими функциями-членами, они должны дополнительно удовлетворять одному из следующих требований:
  • Ровно одна из них является функцией-членом с неявным объектом без квалификатора ссылки, а типы их параметров объекта после удаления ссылок верхнего уровня совпадают.
(начиная с C++23)
  • Их параметры объекта имеют одинаковый тип.

Соответствующие перегрузки шаблонов функций

Два объявления шаблонов функций объявляют соответствующие перегрузки, если оба объявляют шаблоны функций, удовлетворяющие всем следующим условиям:

  • Списки параметров шаблона имеют одинаковую длину.
  • Соответствующие параметры шаблона эквивалентны.
  • У них эквивалентные списки типов параметров, без учета типов явных параметров объекта(начиная с C++23).
  • У них эквивалентные типы возвращаемых значений.
  • Соответствующие параметры шаблона либо объявлены без ограничения, либо объявлены с эквивалентными ограничениями.
  • У них эквивалентные завершающие предложения requires (если имеются).
(начиная с 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 шаблоном функции с эквивалентными списком параметров шаблона и типом.
  • Если одно объявляет E шаблоном псевдонима, другое также должно объявлять E шаблоном псевдонима с эквивалентными списком параметров шаблона и идентификатором типа.
(начиная с C++11)
  • Если одно объявляет E (частичной специализацией) шаблона переменной, другое также должно объявлять E (частичной специализацией) шаблона переменной с эквивалентными списком параметров шаблона и типом.
(начиная с C++14)
  • Если одно объявляет E концептом, другое также должно объявлять E концептом.
(начиная с 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API