[英]Invalid use of incomplete type - why no error in this case?
我很困惑为什么我的代码没有产生错误invalid use of incomplete type
,而我所做的关于此错误的所有阅读建议它应该。
这个问题源于我的代码中具有类似结构的部分出现的错误(如预期),但我无法在一个小例子中重现它(请参阅问题末尾的免责声明 )。
我想要做的总结:
Tree
),我要分配基类型的不同对象First
给它。 First
具体实现具有不同的返回值,因此使用了两个间接级别: First
是抽象基类, First *
用于处理不同的具体实例。 template <typename Type> class TypedFirst : public First
是一个抽象类型,用于定义返回类型为Type
的函数。 ConcreteFirstX
是TypedFirst<Type>
。 在tree.tpp
,为什么对new TF(this)
的调用不会产生invalid use of incomplete type
错误的invalid use of incomplete type
? (在代码中标记了斑点)我认为错误应该存在,因为虽然TF
是模板,但当我使用ConcreteFirstA
, tree.tpp
并不知道它(它不包括concretefirsta.h
甚至是first.h
, 它只向前宣布First
)
可以在pastebin上找到此示例的完整,可编译和可运行的代码。 在这里,为简洁起见,我将排除#define
卫兵和类似的东西。 代码如下:
// tree.h
class First;
class Tree{
public:
Tree() {}
~Tree() {}
template<class TF> // where TF is a ConcreteFirst
void addFirstToTree();
private:
std::map<std::string, First *> firstCollection; // <- "First"'s here
};
#include "tree.tpp"
// tree.tpp
#include "tree.h"
template <class TF> // where TF is a ConcreteFirst
void Tree::addFirstToTree(){
this->firstCollection[TF::name] = new TF(this); // <--- Why does this work?
// ^^^^^^^^^^^^^
}
// first.h
class Tree;
class First{
public:
static const std::string name;
First(const Tree *baseTree) : myTree(baseTree) {}
virtual ~First();
protected:
const Tree *myTree;
};
template <typename Type> class TypedFirst : public First{
public:
static const std::string name;
TypedFirst(const Tree *baseTree) : First(baseTree) {}
Type &value() {return this->_value;}
private:
Type _value;
};
#include "first.tpp"
// first.tpp
#include "first.h"
template <typename Type>
const std::string TypedFirst<Type>::name = "default typed";
// first.cpp
#include "first.h"
First::~First() {}
const std::string First::name = "default";
// concretefirsta.h
#include "first.h"
class ConcreteFirstA : public TypedFirst<int>{
public:
static const std::string name;
ConcreteFirstA(const Tree *baseTree) : TypedFirst<int>(baseTree) {}
~ConcreteFirstA() {}
};
// concretefirsta.cpp
#include "concretefirsta.h"
const std::string ConcreteFirstA::name = "firstA";
最后,代码将所有这些组合在一起并使(in)适当的函数调用:
// main.cpp
#include "tree.h"
#include "first.h"
#include "concretefirsta.h"
int main(){
Tree *myTree = new Tree();
myTree->addFirstToTree<ConcreteFirstA>(); // <-- here! why is this working?
delete myTree;
return 0;
}
免责声明这个问题实际上是由我遇到的一个更大的问题所驱动的,我觉得Stack Overflow格式太大而且无法解决。 即使我最初尝试过这个问题,但问题仍然过于宽泛,我现在试图通过只问一部分问题来挽救它。
我的问题是我一直在一段代码中得到错误 ,结构与此相同:但是,我不能在一个小例子中重现它。
因此,我问为什么下面这段代码没有产生错误 invalid use of incomplete type
(正如我所料),我希望这将有助于我理解和解决我的实际问题。
请不要告诉我这是XY问题的一个例子:我知道我不是在问我的实际问题,因为我(和社区)认为这个格式太大了。
main.cpp
包括tree.h
,它包含(间接)有问题的addFirstToTree()
模板和concretefirsta.h
,它包含ConcreteFirstA
的定义。
稍后在main.cpp
,为ConcreteFirstA
类型实例化addFirstToTree()
:
myTree->addFirstToTree<ConcreteFirstA>(); // <-- here! why is this working?
这是编译器需要足够了解用作模板参数的类型才能编译addFirstToTree()
。 它确实足够了解。 这里是ConcreteFirstA
的完整类型,因为concretefirsta.h
包含了类定义。
早在tree.tpp
中定义了addFirstToTree()
,还没有定义ConcreteFirstA
,但这并不重要。 编译器看到一个模板,并且不知道稍后将实例化该模板的模板参数。 任何依赖于模板参数的函数/ ...(“依赖名称”)都无法在不知道模板将被实例化的参数的情况下解析,因此名称查找/ ...将被推迟到以后。
实例化模板后,编译器会解析所有相关名称并编译特定模板参数的模板。 由于此时ConcreteFirstA
不是一个不完整的类型,因此无误。
因为模板在您使用具体参数进行实例化之前不会进行编译。
当编译器出现时:
myTree->addFirstToTree<ConcreteFirstA>();
它首次使用参数ConcreteFirstA
编译函数addFirstToTree
,这是一个完全已知的类型。
它们是按需编译的,这意味着在需要具有特定模板参数的实例化之前,不会编译模板函数的代码。 此时,当需要实例化时,编译器会专门为模板中的参数生成一个函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.