문제
다음과 같은 동일한 구조의 목록을 포함하는 구조를 만들고 싶습니다.
#include <list>
struct Url
{
CString strUrl;
std::list<Url> children;
};
int main()
{
Url u1, u2;
u1.children.push_back(u2);
}
이 코드는 컴파일되지 않습니다.하지만 교체할 때 std::list
~와 함께 std::vector
잘 작동합니다.이걸 어떻게 작동하게 만들 수 있나요? std::list
?
출력 창에 다음 오류가 포함되어 있습니다.
c:\program files\microsoft visual studio\vc98\include\list(29) : error C2079: '_Value' uses undefined struct 'Url'
E:\test\Test.cpp(23) : see reference to class template instantiation 'std::list<struct Url,class std::allocator<struct Url> >' being compiled
c:\program files\microsoft visual studio\vc98\include\functional(185) : error C2079: 'value' uses undefined struct 'Url'
c:\program files\microsoft visual studio\vc98\include\list(285) : see reference to class template instantiation 'std::binder2nd<struct std::not_equal_to<struct Url> >' being compiled
E:\test\Test.cpp(23) : see reference to class template instantiation 'std::list<struct Url,class std::allocator<struct Url> >' being compiled
해결책
VC6 버그 인 것으로 보이는 작업 라운드가 필요한 경우 목록을 동적으로 만듭니다.
#include <list>
#include <string> // I don't use MFC
struct Url
{
std::string strUrl;
std::list<Url> * children;
Url() {
children = new std::list <Url>;
}
~Url() {
delete children;
}
};
int main()
{
Url u1, u2;
u1.children->push_back(u2);
}
일부는 회원과 동일한 유형의 목록이 허용되는 이유를 물었습니다 (그리고 내 견해로는)
Url array[5];
예를 들어 회원은 그렇지 않을 것입니다. 표준에서도 아무것도 찾을 수 없지만 sizeof( std:;list <T>)
그것이 목록에 의존하지 않습니다. 목록이 (일부 의사 C ++)로 구현되었다고 가정합니다.
list <T> {
listEntry <T> * first;
};
그런 다음 다루어야 할 크기가 없습니다. 질문자 문제를 해결하는 다음의 최소 코드를 고려하십시오.
template <typename T> struct A {
};
struct B {
A <B> b;
};
이것이 합법적이지 않아야한다는 가능한 이유를 알 수 없습니다.
다른 팁
어떤 컴파일러를 사용하고 있는지 알려주시겠습니까? 당신이하는 일에는 본질적으로 잘못된 것이 없습니다. VS2008 SP1에서 다음을 시도했는데 문제가 없습니다.
#include <list>
struct Url
{
std::string name;
std::list<Url> children;
};
int _tmain(int argc, _TCHAR* argv[])
{
Url u1,u2;
u1.children.push_back(u2);
return 0;
}
목록을 포함하는 것을 잊었습니까?
편집하다
OP는 Visual Studio 6.0을 사용하고 있으며 Neil은 실제로 VS6의 버그임을 확인할 수있었습니다.
다른 답변의 주장과는 달리 실제로 ~ 아니다 다음을 포함하여 모든 표준 컨테이너를 인스턴스화하는 것이 합법적입니다. std::list
, 불완전한 유형이 있습니다.( 언어 변호사 이에 대한 논의는 예를 들어 참조하십시오. 여기서 불완전한 유형을 벡터에 대한 템플릿 매개변수로 어떻게 사용할 수 있습니까?)
이 요구 사항은 C++17에서만 완화됩니다. std::forward_list
, std::list
그리고 std::vector
.이전 표준의 경우 최신 버전의 VC 및 gcc에서 작동하는 원본 코드는 비표준 확장입니다.이는 관찰에도 적용됩니다. std::vector
.
C++17 이전 버전에서는 이식 가능한 std::list
어떤 계급의 T
해당 클래스의 구성원으로서 다음과 같은 해결 방법이 필요합니다. std::list<T*>
또는 완화된 요구 사항을 이미 이식 가능하게 구현한 Boost.container 라이브러리를 사용하세요.
C++17에서도 불완전한 유형으로 클래스 템플릿 자체만 인스턴스화할 수 있습니다.멤버가 인스턴스화될 때 유형은 여전히 완전해야 합니다.
흥미 롭습니다 - 당신은 a를 만들려고합니다 vector
또는 list
불완전한 유형. 표준을 간단히 살펴보면 C ++ 표준 라이브러리에 포함 된 컨테이너 유형에 대해 이것이 허용되지 않아야하는지 여부는 아무것도 찾을 수 없습니다. 판결은 합리적 인 것 같습니다.
허용되지 않는 이유 : 유형의 객체를 선언 할 수는 없습니다 X
정의 내부 X
.
예를 들어 다음 코드는 무한대 깊이 데이터 구조를 생성하기 때문에 컴파일에 실패합니다.
struct X {
X x;
};
허용되는 이유 : 대부분의 컨테이너는 실시되므로 실제 데이터 요소에 대한 수준의 간접 (포인터)가 필요합니다. 포인터를 선언하는 것은 합법적입니다.X
정의 내부 X
.
마지막 단락에서 알 수 있듯이이 문제를 해결하는 일반적인 방법은 포인터 또는 참조를 사용하는 것입니다. X
. 예를 들어 다음 두 스 니펫은 잘 컴파일합니다.
struct Y {
Y* y;
};
struct Z {
std::list<Z*> zl;
std::vector<Z*> zv;
};
누구든지 (OK, LITB : -P) 표준 컨테이너 유형에 대한 요구 사항이 무엇인지 알고 있습니까?
코드는 GCC 4.4와 완벽하게 잘 컴파일하고 완벽하게 실행됩니다. 버전 7 이전에 MSVC ++는 완전히 표준을 준수하지 않았습니다. 최신 컴파일러 사용을 고려해야합니다.