代码之家  ›  专栏  ›  技术社区  ›  seanhodges

不完整类型的无效使用

  •  52
  • seanhodges  · 技术社区  · 17 年前

    我试图在我的项目中使用子类中的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’
    
    5 回复  |  直到 17 年前
        1
  •  68
  •   Johannes Schaub - litb    11 年前

    原因是在实例化类模板时,其成员函数的所有声明(而不是定义)也会实例化。当需要专门化的完整定义时,类模板被精确地实例化。例如,当它被用作基类时就是这种情况,就像在您的例子中一样。

    那么会发生什么呢 A<B> 在中实例化

    class B : public A<B>
    

    在哪一点上 B 尚未成为完整类型(位于类定义的右括号之后)。然而 A<B>::action 中国的声明要求 要完整,因为它正在其范围内爬行:

    Subclass::mytype
    

    您需要做的是将实例化延迟到 完成了。一种方法是修改 action 使其成为成员模板。

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

    它仍然是类型安全的,因为如果 var 类型不正确,正在通过 变量 do_action

        2
  •  27
  •   Loki Astari    17 年前

    您可以使用traits类来解决此问题:
    它要求您为每个实际使用的类设置一个特殊的traits类。

    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;
    } 
    
        3
  •  2
  •   sth    17 年前

    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> { ... };
    
        4
  •  1
  •   John Dibling    17 年前

    这不完全是您要求的,但您可以将操作作为模板成员函数:

    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;
    }
    
        5
  •  0
  •   Andreas Magnusson    17 年前

    相反,请尝试:

    void action(const typename Subclass::mytype &var) {
                (static_cast<Subclass*>(this))->do_action();
        }