【问题标题】:Invalid use of incomplete type - why no error in this case?不完整类型的无效使用 - 为什么在这种情况下没有错误?
【发布时间】:2014-09-25 13:56:15
【问题描述】:

我对为什么我的代码没有产生错误invalid use of incomplete type 感到困惑,而我对这个错误所做的所有阅读都表明它应该出现。
问题源于这个错误的出现(如预期的那样)在我的代码部分具有类似的结构,但我无法在 small 示例中重现它(请参阅问题末尾的 disclaimer) .

我正在尝试做的总结:

  • 我有一个结构 (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 错误? (代码中标记了该点)我认为错误应该在那里,因为虽然TF是一个模板,但当我使用ConcreteFirstA时,tree.tpp不知道它(它不包括concretefirsta.h甚至first.h,它向前声明First

可以在here on 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";

最后,将所有这些结合在一起并进行(不)适当的函数调用的代码:

// 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(正如我所料),我希望这对我有帮助了解并解决我的实际问题。

请不要告诉我这是the XY problem 的情况:我知道我不是在问我的实际问题,因为我(和社区)认为它对于这种格式来说太大了。

【问题讨论】:

  • 您是否尝试过“减法”删除代码,直到编译错误消失?另一种技术是预处理有问题的 src 文件并开始删除大量代码,直到它编译没有错误。我假设您正在使用某种版本控制来轻松回滚。

标签: c++ templates incomplete-type


【解决方案1】:

main.cpp 包括tree.h,其中包含(间接)有问题的addFirstToTree() 模板,以及concretefirsta.h,其中包含ConcreteFirstA 的定义。

稍后在main.cpp 中,addFirstToTree() 被实例化为ConcreteFirstA 类型:

myTree->addFirstToTree<ConcreteFirstA>(); // <-- here! why is this working?

这是编译器需要足够了解用作模板参数的类型才能编译addFirstToTree() 的地方。它确实知道得足够多。 ConcreteFirstA 在这里是一个完整的类型,因为 concretefirsta.h 被包含并包含类定义。


早在tree.tpp 中,addFirstToTree() 被定义,ConcreteFirstA 尚未定义,但这没关系。编译器看到一个模板,但不知道该模板稍后将实例化哪些模板参数。任何依赖于模板参数(“依赖名称”)的函数/... 在不知道模板将针对哪些参数实例化的情况下都无法解析,因此名称查找/... 推迟到以后。

一旦模板被实例化并且编译器解析所有依赖名称并为特定模板参数编译模板。由于 ConcreteFirstA 在此时不是不完整的类型,因此它可以正常工作。

【讨论】:

  • 嘿!抱歉回复晚了,我生病了,现在才有时间查看答案。 TY 来回答。所以基本上,为了澄清,我的代码中的另一个标记点​​ new TF(this) (在 tree.tpp 中)尽管 tree.tpp not 包括 concretefirsta.h 仍然有效,因为只有在包含所有内容后才会编译在main.cpp?
【解决方案2】:

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

当编译器走到这行时:

myTree->addFirstToTree<ConcreteFirstA>();

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

cplusplus.com - Templates

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-24
    • 2022-06-10
    • 2014-03-24
    • 1970-01-01
    • 2013-07-22
    • 1970-01-01
    • 1970-01-01
    • 2018-04-10
    相关资源
    最近更新 更多