【发布时间】:2016-01-19 08:35:18
【问题描述】:
这个想法与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);
}
其中_baseTypeList 是std::vector<std::shared_pntr{MyBaseType}> 类型。
在这个函数中,我正在遍历一个组件列表,以查找是否有一个与我要求的类型匹配。如果有,则将转换为该类型的组件返回。否则返回nullptr。
但是,当我从外部代码调用此函数时,出现以下错误:
error C2680: 'MyType*' : invalid target type for dynamic_cast
其中MyType 是派生自组件的某个类。
当我将 #include "MyType.h" 放在标头中时,它编译得很好,但没有它会出现此错误并且无法编译。
这意味着如果不修改这个模板类所在的头文件,我就不能在其他类中使用它,这对我来说是个问题。
有没有一种方法可以实现类似的结果,而无需 #include 我在模板中传递的每个类型的标头?
[编辑] 为清楚起见,考虑一个使用我的库的人,他创建了一个类型 “Foo : MyBaseType”,其中 MyBaseType 有一个虚拟方法“Update”,每帧都会调用它。 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”的定义(但没有给出错误,因为它是在其头文件中前向声明的)。
【问题讨论】:
-
shared_ptr<MyType>对于没有MyType定义的调用者有什么用?无论如何,你不能dynamic_cast或者,就此而言,static_castMyBaseType*到MyType*不知道两者之间的关系。您似乎声称MyType派生自MyBaseType- 但是如果不是通过查看"MyType.h"的内容,编译器应该如何知道这一点? -
调用者确实有“MyType”的定义。我正在制作的一个库只是公开了这个功能。这个库只知道“MyBaseType”,其中“MyType”是一些用户定义的类,它派生自“MyBaseType”。虽然如果这确实不可能,那将是不幸的
-
您不需要在定义
MyClass::GetMyComponent的标头中使用#include "MyType.h"。您确实需要将它包含在调用MyClass::GetMyComponent<MyType>()的源文件中。这真的是太多要求了吗? Live example