C++ 不完整类型的无效使用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/652155/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
invalid use of incomplete type
提问by seanhodges
I'm trying to use a typedef from a subclass in my project, I've isolated my problem in the example below.
我试图在我的项目中使用来自子类的 typedef,我在下面的示例中隔离了我的问题。
Does anyone know where I'm going wrong?
有谁知道我哪里错了?
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;
}
This is the output I get:
这是我得到的输出:
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'
回答by Johannes Schaub - litb
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
所以发生的事情是A<B>
在
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:
此时B
还不是一个完整的类型(它在类定义的右大括号之后)。但是,A<B>::action
的声明需要B
完整,因为它在它的范围内爬行:
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.
您需要做的是将实例化延迟到B
完成的某个点。一种方法是修改 的声明action
以使其成为成员模板。
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.
它仍然是类型安全的,因为如果var
不是正确的类型,传递var
到do_action
将失败。
回答by Martin York
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;
}
回答by sth
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.
您B
从派生A<B>
,因此编译器在看到类的定义后所做的第一件事B
就是尝试实例化A<B>
。为此,它需要知道B::mytype
的参数action
。但是由于编译器只是在弄清楚 的实际定义的过程中B
,它还不知道这种类型,并且您会收到错误消息。
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> { ... };
回答by John Dibling
Not exactly what you were asking, but you can make action a template member function:
不完全是您要问的,但是您可以将 action 设为模板成员函数:
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;
}
回答by Andreas Magnusson
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();
}