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

달리 명시되지 않는 한, 두 선언은 동일한 개체를 (재)도입할 수 없습니다. 이러한 선언이 존재하는 경우 프로그램은 형식이 잘못되었습니다.

목차

해당 선언

두 선언은 다음의 경우를 제외하고 동일한 이름을 (재)도입하거나, 둘 다 생성자를 선언하거나, 둘 다 소멸자를 선언할 때 일치합니다(correspond) .

  • 하나는 using 선언 이거나,
  • 하나는 타입을 선언하고( typedef 이름 이 아님) 다른 하나는 변수, 익명 공용체 가 아닌 비정적 데이터 멤버, 열거자, 함수, 또는 함수 템플릿을 선언하거나,
  • 각각 함수 또는 함수 템플릿을 선언하고 이들이 해당 오버로드를 선언하지 않는 경우.

해당 함수 오버로드

두 개의 function declarations 은 다음의 모든 조건을 충족하는 함수를 선언할 경우 해당 오버로드들 을 선언한다고 합니다:

(C++20부터)
  • 둘 다 비정적 멤버 함수인 경우, 다음 요구 사항 중 하나를 추가로 충족해야 합니다:
  • 그들 중 정확히 하나가 ref-qualifier가 없는 암시적 객체 멤버 함수 이고, 최상위 참조를 제거한 후의 객체 매개변수 타입이 동일한 경우.
(C++23부터)
  • 해당 객체 매개변수들은 동일한 타입을 가집니다.

대응하는 함수 템플릿 오버로드

두 개의 함수 템플릿 선언 은 다음의 모든 조건을 만족하는 함수 템플릿을 선언할 경우 상응하는 오버로드 를 선언합니다:

  • 해당 템플릿 매개변수들은 둘 다 constraint 없이 선언되었거나, 둘 다 동등한 제약 조건으로 선언된 경우
  • 동등한 후행 requires clauses 를 가짐 (있는 경우)
(C++20부터)
  • 둘 다 비정적 멤버 함수 템플릿인 경우, 다음 요구 사항 중 하나를 추가로 충족해야 합니다:
  • 둘 중 정확히 하나가 ref-qualifier가 없는 암시적 객체 멤버 함수 템플릿이고, 참조를 모두 제거한 후의 객체 매개변수 타입이 동등한 경우.
(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 재선언(redeclaration) 입니다. 그렇지 않다면, 그것은 X 최초 선언(first declaration)  입니다.

제한 사항

어떤 엔티티 E 의 두 선언이 아래 해당 제한을 위반하는 경우, 프로그램은 ill-formed입니다:

  • 한쪽에서 E 를 변수로 선언하면, 다른 쪽에서도 E 를 동일한 타입의 변수로 선언해야 합니다.
  • 한쪽에서 E 함수 로 선언하면, 다른 쪽에서도 E 를 동일한 타입의 함수로 선언해야 합니다.
  • 한쪽에서 E 열거자 로 선언하면, 다른 쪽에서도 E 를 열거자로 선언해야 합니다.
  • 한쪽에서 E 네임스페이스 로 선언하면, 다른 쪽에서도 E 를 네임스페이스로 선언해야 합니다.
  • 한쪽에서 E 클래스 타입 으로 선언하면, 다른 쪽에서도 E 를 클래스 타입으로 선언해야 합니다.
  • 한쪽에서 E 열거형 타입 으로 선언하면, 다른 쪽에서도 E 를 열거형 타입으로 선언해야 합니다.
  • 한쪽에서 E 클래스 템플릿 으로 선언하면, 다른 쪽에서도 E 를 동등한 템플릿 매개변수 목록을 가진 클래스 템플릿으로 선언해야 합니다( 함수 템플릿 오버로딩 참조).
  • 한쪽에서 E 함수 템플릿 으로 선언하면, 다른 쪽에서도 E 를 동등한 템플릿 매개변수 목록과 타입을 가진 함수 템플릿으로 선언해야 합니다.
  • 만약 한 선언에서 E alias template 로 선언한다면, 다른 선언에서도 E 를 동등한 템플릿 매개변수 목록과 type-id 를 갖는 alias template로 선언해야 합니다.
(C++11부터)
  • 만약 한 선언에서 E 를 (부분 특수화된) variable template 로 선언한다면, 다른 선언에서도 E 를 동등한 템플릿 매개변수 목록과 타입을 갖는 (부분 특수화된) variable template로 선언해야 합니다.
(C++14부터)
  • 만약 한 선언에서 E concept 로 선언한다면, 다른 선언에서도 E 를 concept으로 선언해야 합니다.
(C++20부터)

타입은 모든 타입 조정 후에 비교됩니다(이 과정에서 typedefs 는 해당 정의로 대체됩니다). 배열 객체에 대한 선언은 주요 배열 경계의 존재 여부에 따라 다른 배열 타입을 지정할 수 있습니다. 두 선언이 서로 도달 가능하지 않은 경우 진단이 요구되지 않습니다.

void g();      // #1
void g(int);   // OK, #1과 다른 엔티티 (서로 대응되지 않음)
int g();       // 오류: #1과 동일한 엔티티이지만 다른 타입
void h();      // #2
namespace h {} // 오류: #2와 동일한 엔티티이지만 함수가 아님

내부 연결성(internal linkage)을 가진 이름을 선언하는 선언문 H 가 다른 번역 단위(translation unit) U 에 있는 선언문 D 앞에 위치하고, H U 에 나타났을 때 D 와 동일한 개체(entity)를 선언하게 된다면, 해당 프로그램은 형식에 맞지 않습니다(ill-formed).

잠재적으로 충돌하는 선언

두 선언은 잠재적으로 충돌할 수 있습니다 만약 이들이 서로 대응하지만 다른 개체를 선언하는 경우.

어떤 범위에서든 이름이 두 선언 A B 에 바인딩되고 이들이 잠재적으로 충돌하는 경우 , B 가 이름 독립적이지 않으며 (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 _; // C++26부터 OK, 이름 독립 선언
    _ = 0; // 오류: 조회 집합에 두 개의 비함수 선언 존재
}
void h ()
{
    int _;        // #1
    _ ++;         // OK
    static int _; // 오류: #1과 충돌 (정적 변수는 이름 독립적이지 않음)
                  // 
}

결함 보고서

다음 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
CWG 279
( P1787R6 )
C++98 연결 목적을 위한 typedef 이름을 가진 이름 없는 클래스나 열거형을
재선언할 수 있는지 여부가 불분명했음
재선언 가능함
CWG 338
( P1787R6 )
C++98 연결 목적을 위한 이름으로 열거자를 가진 이름 없는 열거형을
재선언할 수 있는지 여부가 불분명했음
재선언 가능함
CWG 1884
( P1787R6 )
C++98 동일한 엔티티의 다중 선언에 적용되는
제한 사항이 불분명했음
명확히 규정됨