invalid use of incomplete type

后端 未结 5 1606
北海茫月
北海茫月 2020-11-30 01:43

I\'m trying to use a typedef from a subclass in my project, I\'ve isolated my problem in the example below.

Does anyone know where I\'m going wrong?

         


        
相关标签:
5条回答
  • 2020-11-30 02:03

    You need to use a pointer or a reference as the proper type is not known at this time the compiler can not instantiate it.

    Instead try:

    void action(const typename Subclass::mytype &var) {
                (static_cast<Subclass*>(this))->do_action();
        }
    
    0 讨论(0)
  • 2020-11-30 02:04

    You derive B from A<B>, so the first thing the compiler does, once it sees the definition of class B is to try to instantiate A<B>. To do this it needs to known B::mytype for the parameter of action. But since the compiler is just in the process of figuring out the actual definition of B, it doesn't know this type yet and you get an error.

    One way around this is would be to declare the parameter type as another template parameter, instead of inside the derived class:

    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> { ... };
    
    0 讨论(0)
  • 2020-11-30 02:14

    The reason is that when instantiating a class template, all its declarations (not the definitions) of its member functions are instantiated too. The class template is instantiated precisely when the full definition of a specialization is required. That is the case when it is used as a base class for example, as in your case.

    So what happens is that A<B> is instantiated at

    class B : public A<B>
    

    at which point B is not a complete type yet (it is after the closing brace of the class definition). However, A<B>::action's declaration requires B to be complete, because it is crawling in the scope of it:

    Subclass::mytype
    

    What you need to do is delaying the instantiation to some point at which B is complete. One way of doing this is to modify the declaration of action to make it a member template.

    template<typename T>
    void action(T var) {
        (static_cast<Subclass*>(this))->do_action(var);
    }
    

    It is still type-safe because if var is not of the right type, passing var to do_action will fail.

    0 讨论(0)
  • 2020-11-30 02:20

    You can get around this by using a traits class:
    It requires you set up a specialsed traits class for each actuall class you use.

    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;
    } 
    
    0 讨论(0)
  • 2020-11-30 02:22

    Not exactly what you were asking, but you can make action a template member function:

    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;
    }
    
    0 讨论(0)
提交回复
热议问题