Namespaces
Variants

Conflicting declarations

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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

Содержание

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

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

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

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

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

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

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

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

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