문제
내 프로젝트의 하위 클래스에서 typedef를 사용하려고 하는데 아래 예제에서 내 문제를 격리했습니다.
내가 어디로 잘못 가고 있는지 아는 사람이 있습니까?
template<typename Subclass>
class A {
public:
//Why doesn't it like this?
void action(typename Subclass::mytype var) {
(static_cast<Subclass*>(this))->do_action(var);
}
};
class B : public A<B> {
public:
typedef int mytype;
B() {}
void do_action(mytype var) {
// Do stuff
}
};
int main(int argc, char** argv) {
B myInstance;
return 0;
}
이것은 내가 얻는 결과입니다.
sean@SEAN-PC:~/Documents/LucadeStudios/experiments$ g++ -o test test.cpp
test.cpp: In instantiation of ‘A<B>’:
test.cpp:10: instantiated from here
test.cpp:5: error: invalid use of incomplete type ‘class B’
test.cpp:10: error: forward declaration of ‘class B’
해결책
그 이유는 클래스 템플릿을 인스턴스화할 때 해당 멤버 함수의 모든 선언(정의가 아님)도 인스턴스화되기 때문입니다.클래스 템플릿은 전문화의 전체 정의가 필요할 때 정확하게 인스턴스화됩니다.예를 들어 귀하의 경우와 같이 기본 클래스로 사용되는 경우입니다.
그래서 무슨 일이 일어나는가? A<B>
인스턴스화됩니다
class B : public A<B>
어느 시점에서 B
아직 완전한 유형이 아닙니다(클래스 정의의 닫는 중괄호 뒤에 있음).하지만, A<B>::action
의 선언에는 다음이 필요합니다. B
범위 내에서 크롤링 중이므로 완료됩니다.
Subclass::mytype
당신이 해야 할 일은 인스턴스화를 어느 시점까지 지연시키는 것입니다. B
완료되었습니다.이를 수행하는 한 가지 방법은 선언을 수정하는 것입니다. action
이를 구성원 템플릿으로 만듭니다.
template<typename T>
void action(T var) {
(static_cast<Subclass*>(this))->do_action(var);
}
여전히 유형 안전합니다. var
올바른 유형이 아닙니다. 통과합니다. var
에게 do_action
실패할 것이다.
다른 팁
특성 클래스를 사용 하여이 문제를 해결할 수 있습니다.
사용하는 각 Actuall 클래스에 대해 특별한 특성 클래스를 설정해야합니다.
template<typename SubClass>
class SubClass_traits
{};
template<typename Subclass>
class A {
public:
void action(typename SubClass_traits<Subclass>::mytype var)
{
(static_cast<Subclass*>(this))->do_action(var);
}
};
// Definitions for B
class B; // Forward declare
template<> // Define traits for B. So other classes can use it.
class SubClass_traits<B>
{
public:
typedef int mytype;
};
// Define B
class B : public A<B>
{
// Define mytype in terms of the traits type.
typedef SubClass_traits<B>::mytype mytype;
public:
B() {}
void do_action(mytype var) {
// Do stuff
}
};
int main(int argc, char** argv)
{
B myInstance;
return 0;
}
당신은 파생됩니다 B
~에서 A<B>
, 클래스의 정의를 볼 때 컴파일러가 가장 먼저하는 일은 B
인스턴스팅을 시도하는 것입니다 A<B>
. 이를 위해서는 알려야합니다 B::mytype
매개 변수의 경우 action
. 그러나 컴파일러는 단지의 실제 정의를 파악하는 과정에 있습니다. B
, 아직이 유형을 알지 못하고 오류가 발생합니다.
이 주위의 한 가지 방법은 파라미터 유형을 파생 클래스 내부 대신 다른 템플릿 매개 변수로 선언하는 것입니다.
template<typename Subclass, typename Param>
class A {
public:
void action(Param var) {
(static_cast<Subclass*>(this))->do_action(var);
}
};
class B : public A<B, int> { ... };
정확히 당신이 요청한 것이 아니라 템플릿 멤버 기능을 만들 수 있습니다.
template<typename Subclass>
class A {
public:
//Why doesn't it like this?
template<class V> void action(V var) {
(static_cast<Subclass*>(this))->do_action();
}
};
class B : public A<B> {
public:
typedef int mytype;
B() {}
void do_action(mytype var) {
// Do stuff
}
};
int main(int argc, char** argv) {
B myInstance;
return 0;
}
현재 컴파일러가 인스턴스화 할 수없는 적절한 유형이 알려지지 않았으므로 포인터 나 참조를 사용해야합니다.
대신 시도해보십시오 :
void action(const typename Subclass::mytype &var) {
(static_cast<Subclass*>(this))->do_action();
}