IT이야기

불완전한 유형의 잘못된 사용

cyworld 2021. 5. 1. 09:33
반응형

불완전한 유형의 잘못된 사용


내 프로젝트의 하위 클래스에서 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통과, 권리 유형이 아닌 vardo_action실패합니다.


특성 클래스를 사용하여이 문제를 해결할 수 있습니다. 사용하는
각 실제 클래스에 대해 특수 특성 클래스를 설정해야합니다.

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();
    }

ReferenceURL : https://stackoverflow.com/questions/652155/invalid-use-of-incomplete-type

반응형