铸造成未申报类型

问题描述:

该想法与通用版本GetComponent() in Unity相同。但我目前绊在下面的模板问题:铸造成未申报类型

template<class T> std::shared_ptr<T> MyClass::GetMyComponent() 
{ 
    for (int i = 0; i < _baseTypeList.size(); i++) 
    { 
     auto base = _baseTypeList[i]; 
     T* check = dynamic_cast<T*>(base.get()); 
     if (check) 
     { 
      return std::static_pointer_cast<T>(base); 
     } 
    } 
    return std::shared_ptr<T>(nullptr); 
} 

其中_baseTypeListstd::vector<std::shared_pntr{MyBaseType}>类型。

在此函数中,我遍历组件列表以查找是否存在与我所要求的类型相匹配的组件。如果有,则将组件转换为该类型。否则返回nullptr

然而,当我打电话从外面代码这个功能,我得到以下错误:

error C2680: 'MyType*' : invalid target type for dynamic_cast 

其中MyType是一些类,从组件派生。

当我把#include "MyType.h"放在头文件中时,它编译得很好,但没有它,它会给出这个错误并且不会编译。

这意味着我不能在没有修改此模板类所在的头文件的情况下在其他类中使用它,这对我来说是个问题。

有没有一种方法可以实现同样的结果,而不必#include我在模板中传递的每一个类型的标题都是?为了清楚起见,考虑一个人使用我的库,他创建了一个类型 “Foo:MyBaseType”,其中MyBaseType有一个虚拟方法“更新”,每帧调用一次。 类MyBaseType(包括Foo)的任何实例都要由此库管理,并且每个帧都有更新。 该库因此具有大量“MyBaseType”对象。但是并不知道它们的实际类型,只是它们来源于“MyBaseType”,所以它可以对它们调用Update()。

如果我需要特定的类型,库需要能够在此列表中搜索并返回它。 我想这个“搜索”在图书馆自身的情况发生,所以我没有揭露列表,谱写新的“搜索”的方法为每一个从“MyBaseType”

[最后] 派生型事实证明,我搞乱了我的项目中的包括订单。 什么,我试图做一个最小的例子是:

#include <stdio.h> 
#include <tchar.h> 
#include <iostream> 
#include <memory> 
#include "vector" 

class MyBaseClass 
{ 
    virtual void Update(){}; 
}; 

class MyLibrary 
{ 
public: 
    template<class T> std::shared_ptr<T> GetComponent(); 
    std::vector<std::shared_ptr<MyBaseClass>> list; 
}; 

template<class T> std::shared_ptr<T> MyLibrary::GetComponent() 
{ 
    static_assert(std::is_base_of<MyBaseClass, T>::value, "T1 is no subclass of ModelComponent"); 
    for (unsigned int i = 0; i < list.size(); i++) 
    { 
     auto comp = list[i]; 
     T* check = dynamic_cast<T*>(comp.get()); 
     if (check) 
     { 
      return std::static_pointer_cast<T>(comp); 
     } 
    } 
    return std::shared_ptr<T>(nullptr); 
} 

class MyClass : public MyBaseClass 
{ 
    void Update() override; 
}; 

void MyClass::Update() 
{ 

} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    MyLibrary lib; 
    lib.list.push_back(std::make_shared<MyClass>()); 
    auto var = lib.GetComponent<MyClass>(); 
    std::cout << (var ? "var is object" : "var is not") << std::endl; 

    while (true) 
    { 

    } 
    return 0; 
} 

预期其工作。

主要问题是编译器在“GetMyComponent”函数中给出了一个错误,所以我找到了它的一个用法,它完成了所有建议。

但事实证明,第二种用法在调用它之前没有定义“MyClass”(但没有给出错误,因为它在头文件中是前向声明的)。

+1

有什么用'shared_ptr的'到没有'MyType'的定义呼叫者?无论如何,在不知道两者是如何相互关联的情况下,你不能'dynamic_cast'或者就此而言'static_cast'' MyBaseType *'到'MyType *'。您似乎声称'MyType'派生自'MyBaseType' - 但编译器应该如何知道,如果不是通过查看“MyType.h”的内容? –

+0

调用者确实拥有“MyType”的辩护。我正在做一个库,只是公开这个函数。该库仅具有“MyBaseType”的知识,其中“MyType”是从“MyBaseType”派生的一些用户定义的类。虽然这是不幸的,如果这确实是不可能的 –

+0

你不需要在定义MyClass :: GetMyComponent的头文件中包含“#include”MyType.h“'。您确实需要将其包含在调用'MyClass :: GetMyComponent ()'的源文件中。这真的太难问了吗? [Live example](http://rextester.com/VJH95253) –

您不需要在您的标头中包含可能的T类型的定义。你需要在翻译单元定义有关的一个利用模板扩展:

// client.cpp 
#include <myclass.h> 
#include <foo.h> // defines class Foo 

void f(MyClass *p) 
{ 
    auto c = p->GetMyComponent<Foo>(); 
    c->foobar(); 
} 
+0

是的,这正是我正在做的。 'auto myvar = MyClass * - > GetMyComponent ();' 我没有在我的头文件中包含任何类型,只是我发布的函数。 然而,编译器告诉我必须将“MyType”添加到头部,否则它不会编译 –

+0

@Brian:很难分辨出你在做什么。您能否编辑您的问题,以便该示例是[最小化,完成和可验证](/ help/mcve)?我不相信你有相当于我上面的'#include ';一个MCVE可能会帮助我重现您的问题并给出更好的答案。 –

+0

哦,并包含你的编译器的错误信息。我怀疑这是告诉你添加一个include _to header_,仅仅是类型的使用位置。 –