문제

내 프로젝트의 하위 클래스에서 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();
    }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top