이중 콜론을 사용하여 네임 스페이스에서 클래스를 전달할 수없는 이유는 무엇입니까?


164
class Namespace::Class;

왜 이렇게해야합니까? :

namespace Namespace {
    class Class;
}

컴파일러는 VC ++ 8.0을 사용하여 다음을 발행합니다.

오류 C2653 : 'Namespace': 클래스 또는 네임 스페이스 이름이 아닙니다.

여기서 문제는 컴파일러 Namespace가 클래스인지 네임 스페이스 인지 알 수 없다는 것입니다 . 그러나 왜 이것이 전진 선언이기 때문에 이것이 중요합니까?

네임 스페이스에 정의 된 클래스를 전달하는 다른 방법이 있습니까? 위의 구문은 네임 스페이스를 "다시 열고"정의를 확장 한 것 같습니다. Class실제로 정의되지 않은 경우 어떻게해야 Namespace합니까? 이로 인해 어느 시점에서 오류가 발생합니까?


44
여기에있는 모든 답변에 동의하지 않고 언어의 디자인 버그 일뿐입니다. 그들은 더 잘 생각할 수있었습니다.
Pavel Radzivilovsky

이것은 C ++ (주관적 인)에서 이것이 왜 불법인지에 대한 토론으로 향하고 있으며 논쟁의 여지가 있습니다. 마감 투표.
David Thornley

7
어떻게 컴파일러에서 알고하도록되어 A::B(가) A네임 스페이스 식별자 대신 클래스 이름입니까?
David R Tribble

@ STingRaySC : 토론은 C ++이 왜 그렇게하는지에 대한 명확한 대답이 없으므로 주관적입니다. (질문은 이미 답변 된 객관적인 답변이있는 일부 질문이 포함 된 산탄 총 질문입니다.)이 시점에서 저는 미션의 흔적에 민감 해졌으며 이는 C ++의 잘못된 기능이라는 파벨과의 동의에 해당합니다. Namespace클래스 또는 네임 스페이스 인지 왜 중요한지에 대한 질문에는 아무런 문제가 없습니다 . 구문과의 언어 화염 전쟁을 시작할 가능성이 있다는 힌트를 얻지 마십시오.
David Thornley

답변:


85

당신이 할 수 없기 때문에. C ++ 언어에서 정규화 된 이름은 기존 (즉, 이전에 선언 된) 엔터티 를 참조하는 데만 사용됩니다 . 새로운 엔터티 를 소개하는 데 사용할 수 없습니다 .

그리고 당신은 있는 새로운 엔티티를 선언하는 네임 스페이스를 "재개"사실. 클래스 Class가 나중에 다른 네임 스페이스의 멤버로 정의 된 경우 여기에서 선언 한 클래스와 관련이없는 완전히 다른 클래스입니다.

미리 선언 된 클래스 를 정의 할 때 네임 스페이스를 다시 "열지 않아도"됩니다. 전역 네임 스페이스 (또는를 묶는 네임 스페이스 Namespace)에서 다음과 같이 정의 할 수 있습니다.

class Namespace::Class {
  /* whatever */
};

네임 스페이스에서 이미 선언 된 엔터티를 참조하고 Namespace있으므로 정규화 된 이름을 사용할 수 있습니다 Namespace::Class.


10
@STingRaySC : 중첩 클래스를 전달 선언하는 유일한 방법은 선언을 묶는 클래스 의 정의 안에 넣는 것 입니다. 그리고 둘러싼 클래스를 정의하기 전에 중첩 클래스를 전달할 방법이 없습니다.
AnT

@ STingRaySC : 중첩 클래스는 fwd 선언 될 수 있습니다-내 대답을 참조하십시오.
John Dibling

8
@John Dibling : 중첩 클래스 는 다른 클래스 내에 선언 된 클래스 입니다. 네임 스페이스 내에서 즉시 선언 된 클래스는 중첩 클래스가 아닙니다. 답에 센세이션 수업은 없습니다.
AnT

198

당신은 정답을 얻고 있습니다, 다시 단어를 써 보도록하겠습니다.

class Namespace::Class;

왜 이렇게해야합니까?

이 용어 Namespace::Class는 컴파일러에 다음 과 같은 의미를주기 때문에이 작업을 수행해야합니다 .

... OK, 컴파일러. 네임 스페이스라는 네임 스페이스를 찾으십시오.이 네임 스페이스에서 Class라는 클래스를 참조하십시오.

그러나 컴파일러는 네임 스페이스를 모르기 때문에 무슨 말을하는지 알지 못합니다 Namespace. 다음 Namespace과 같이 이라는 네임 스페이스가있는 경우에도

namespace Namespace
{
};

class Namespace::Class;

네임 스페이스 외부에서 네임 스페이스 내에서 클래스를 선언 할 수 없으므로 여전히 작동하지 않습니다. 네임 스페이스에 있어야합니다.

따라서 실제로 네임 스페이스 내에 클래스를 선언 할 수 있습니다. 그냥 이렇게 :

namespace Namespace
{
    class Class;
};

39
다른 모든 대답은 혼란 스러웠지만 "이 네임 스페이스 외부에서 네임 스페이스 내에 클래스를 선언 할 수 없습니다. 네임 스페이스에 있어야합니다." 기억하기에 매우 유용한 힌트였습니다.
dashesy

22

중첩 된 네임 스페이스를 한 번에 선언 할 수없는 것과 같은 이유로 다음과 같이 가정합니다.

namespace Company::Communications::Sockets {
}

그리고 당신은 이것을해야합니다 :

namespace Company {
  namespace Communications {
    namespace Sockets {
    }
  }
}

1
이것은 실제로 왜 당신이 그것을 할 수 없는지를 설명하는 대답이 아닙니다.
스타 파일럿

6
이것은 많은 시간을 절약 한 답변입니다
Kadir Erdem Demir

17
C ++ 17이 이것을 추가합니다.
rparolin

여기서 여러분은 모두 네임 스페이스라는 것을 알고 있습니다. 그러나 Company :: Communications :: Socket 클래스를 사용하면 Communications가 네임 스페이스인지 클래스인지 (소켓이 중첩 클래스인지) 알 수 없습니다.
Lothar

12

전달 선언 변수의 유형이 실제로 무엇인지는 명확하지 않습니다. 앞으로의 선언 class Namespace::Class;

namespace Namespace {
  class Class;
}

또는

class Namespace {
public:
  class Class;
};


6
이것이 가장 좋은 대답 중 하나라고 생각합니다. 왜냐하면 이것이 컴파일러 자체에서 쉽게 결정할 수 없는지에 대한 대답이기 때문입니다.
Devolus

1

그것을 거부하는 데 관련된 이론적 근거에 대한 훌륭한 답변이 많이 있습니다. 나는 단지 지루한 표준 조항을 구체적으로 금지하고 있습니다. 이것은 C ++ 17 (n4659)에서도 마찬가지입니다.

해당 단락은 [class.name] / 2입니다 .

클래스 키 식별자 로만 구성된 선언 ; 현재 범위에서 이름을 다시 선언하거나 식별자를 클래스 이름으로 전달하여 선언 한 것입니다. 클래스 이름을 현재 범위로 소개합니다.

위에서 포워드 선언 (또는 클래스의 선언)을 구성하는 요소를 정의했습니다. 본질적으로, 그 중 하나 여야 class identifier;, struct identifier;또는 union identifier;여기서 식별자는 에서 공통 사전 정의는 [lex.name]은 :

identifier:
  identifier-nondigit
  identifier identifier-nondigit
  identifier digit
identifier-nondigit:
  nondigit
  universal-character-name
nondigit: one of
  a b c d e f g h i j k l m
  n o p q r s t u v w x y z
  A B C D E F G H I J K L M
  N O P Q R S T U V W X Y Z _
digit: one of
  0 1 2 3 4 5 6 7 8 9

다음은 [a-zA-Z_][a-zA-Z0-9_]*우리 모두에게 익숙한 공통 구성표의 제작입니다 . 보다시피, 이것은 식별자가 아니기 class foo::bar;때문에 유효한 정방향 선언 foo::bar이되지 않습니다. 완전한 이름이며 다른 이름입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.