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

pen*_*ope 9 c++ templates incomplete-type

我很困惑为什么我的代码没有产生错误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错误?(在代码中标记了斑点)我认为错误应该在那里,因为,虽然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?
  //                                ^^^^^^^^^^^^^      
}
Run Code Online (Sandbox Code Playgroud)
// 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";
Run Code Online (Sandbox Code Playgroud)
// 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";
Run Code Online (Sandbox Code Playgroud)

最后,代码将所有这些组合在一起并使(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;
}
Run Code Online (Sandbox Code Playgroud)

免责声明这个问题实际上是由我遇到的一个更大的问题所驱动的,我觉得Stack Overflow格式太大而且无法解决.即使我最初尝试过这个问题,但问题仍然过于宽泛,我现在试图通过只问一部分问题来挽救它.

我的问题是我在一段代码中不断得到错误,但是,我不能在一个小例子中重现它.

因此,我问为什么下面的代码不会产生错误 invalid use of incomplete type(正如我所料),我希望这将有助于我理解和解决我的实际问题.

请不要告诉我这是XY问题的一个例子:我知道我不是在问我的实际问题,因为我(和社区)认为这个格式太大了.

Rip*_*ple 1

因为在您使用具体参数实例化模板之前,不会编译模板。

当编译器到达该行时:

myTree->addFirstToTree<ConcreteFirstA>();
Run Code Online (Sandbox Code Playgroud)

addFirstToTree它使用参数第一次编译函数ConcreteFirstA,这是那里完全已知的类型。

请参阅cplusplus.com - 模板

它们是按需编译的,这意味着直到需要使用特定模板参数进行实例化时才编译模板函数的代码。此时,当需要实例化时,编译器会专门为模板中的这些参数生成一个函数。