我正在尝试在项目中使用子类的typedef,我在下面的示例中已经分离了我的问题.
有谁知道我哪里出错了?
templateclass A { public: //Why doesn't it like this? void action(typename Subclass::mytype var) { (static_cast (this))->do_action(var); } }; class B : public A { 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’: 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’
Johannes Sch.. 63
原因是,在实例化类模板时,其成员函数的所有声明(而不是定义)也会被实例化.当需要完整定义特化时,将精确地实例化类模板.例如,在它被用作基类时就是这种情况,就像你的情况一样.
所以会发生什么A
是实例化的
class B : public A
此时B
还不是一个完整的类型(它是在类定义的结束括号之后).但是,A::action
声明需要B
完整,因为它在它的范围内爬行:
Subclass::mytype
您需要做的是将实例化延迟到B
完成的某个点.这样做的一种方法是修改声明action
以使其成为成员模板.
templatevoid action(T var) { (static_cast (this))->do_action(var); }
它仍然是类型安全的,因为如果var
是不正确的类型,传递var
到do_action
将失败.
原因是,在实例化类模板时,其成员函数的所有声明(而不是定义)也会被实例化.当需要完整定义特化时,将精确地实例化类模板.例如,在它被用作基类时就是这种情况,就像你的情况一样.
所以会发生什么A
是实例化的
class B : public A
此时B
还不是一个完整的类型(它是在类定义的结束括号之后).但是,A::action
声明需要B
完整,因为它在它的范围内爬行:
Subclass::mytype
您需要做的是将实例化延迟到B
完成的某个点.这样做的一种方法是修改声明action
以使其成为成员模板.
templatevoid action(T var) { (static_cast (this))->do_action(var); }
它仍然是类型安全的,因为如果var
是不正确的类型,传递var
到do_action
将失败.
你可以通过使用traits类来解决这个问题:
它要求你为你使用的每个实际类设置一个特殊的traits类.
templateclass SubClass_traits {}; template class A { public: void action(typename SubClass_traits ::mytype var) { (static_cast (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 { public: typedef int mytype; }; // Define B class B : public A { // Define mytype in terms of the traits type. typedef SubClass_traits::mytype mytype; public: B() {} void do_action(mytype var) { // Do stuff } }; int main(int argc, char** argv) { B myInstance; return 0; }