繁体   English   中英

使用不完整类型无效 - 为什么在这种情况下没有错误?

[英]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的函数。
  • 最后, ConcreteFirstXTypedFirst<Type>

tree.tpp ,为什么对new TF(this)的调用不会产生invalid use of incomplete type错误的invalid use of incomplete type (在代码中标记了斑点)我认为错误应该存在,因为虽然TF是模板,但当我使用ConcreteFirstAtree.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 ,这是一个完全已知的类型。

请参阅cplusplus.com - 模板

它们是按需编译的,这意味着在需要具有特定模板参数的实例化之前,不会编译模板函数的代码。 此时,当需要实例化时,编译器会专门为模板中的参数生成一个函数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM