创建泛型转换函数
Creating a generic conversion function
我有一个ResourceManager
,它接受类型为Resource
的类。Resource
是ShaderProgram
、Texture
、Mesh
甚至Camera
等完全不相关的其他类的父类。
ResourceManager
是有效的。但是有一件事是非常乏味和烦人的,那就是当我从ResourceManager
检索对象时。问题在这里:
为了从ResourceManager
获得一个对象,你调用以下两个函数之一:
static Resource* get(int id);
static Resource* get(const std::string &name);
第一个函数通过一个整数id检查一个std::unordered_map
;而第二个函数通过客户端手动给出的名称检查另一个std::unordered_map
。出于灵活性考虑,我有两个版本的这些函数,因为有时我们不关心ResourceManager中包含的对象是什么(如Mesh
),有时我们关心它是什么(如Camera
或ShaderProgram
),因为我们可能希望通过名称而不是id检索所述对象。
无论哪种方式,两个函数都返回指向Resource
的指针。当您调用该函数时,就像这样简单:
rm::get("skyboxShader");
其中rm
只是ResourceManager
的typedef
,因为该类是静态的(所有成员/函数都是静态的)。问题是,rm::get(..)
函数返回的是Resource*
,而不是一开始添加到ResourceManager
的子类。所以,为了解决这个问题,我必须做一个手动类型转换,这样我就可以得到ShaderProgram*
而不是Resource*
。我是这样做的:
auto s = static_cast<ShaderProgram*>(rm::get(name));
所以,每次我想访问Resource
时,我必须插入我想要实际进入static_cast
的类型。这是有问题的,因为每次有人需要访问Resource
时,他们必须键入转换它。所以,我自然地创建了一个函数,并且ShaderProgram是这里的主题,因此:
ShaderProgram* Renderer::program(const std::string &name)
{
auto s = static_cast<ShaderProgram*>(rm::get(name));
return s;
}
这个函数是静态的,而ResourceManager
是一个静态类,所以两者可以很好地结合在一起。这是一个很好的辅助函数,它有效地工作,我的程序渲染结果很好。问题是当我处理其他Resource
时,我必须做什么;这意味着对于每个存在的Resource
,都必须有一个类型转换函数来容纳它。这很烦人。有没有一种方法可以写一个类似这样的泛型类型转换函数?
auto Renderer::getResource(classTypeYouWant T, const std::string &name)
{
auto s = static_cast<T*>(rm::get(name));
return s;
}
在这里,auto关键字使函数派生出它应该处理的类型并相应地返回结果。我的第一个猜测是,我可能不得不使用模板;但模板的问题是,我不能限制哪些类型插入到函数中,我真的真的不想要浮点id数,char id,更不用说自定义的id。它要么是字符串(可能会更改为const char* tbh),要么是整型,或者其他类型。
如何创建像上面描述的那样的通用转换函数?
您看过使用dynamic_cast
吗?如果使用dynamic_cast
转换失败,指针将被设置为nullptr
。因此,您可以为每种类型编写重载,也可以编写模板函数,其中传递要转换为的类型以及字符串或id,如果转换成功或失败,则返回true
或false
。
template<typename T>
bool Renderer::getResource(T*& type, const std::string &name)
{
type = dynamic_cast<decltype(std::remove_reference<decltype(T)>::type)>(rm::get(name));
if (type == nullptr)
return false;
return true;
}
好吧,我不喜欢无类型存储的想法,但也许您可以将基本程序作为起点。有很多东西必须美化,但有些作品必须保留:-)
再次强调:用这种方式解决问题是设计上的失败!
除了您的示例代码之外,此解决方案在检查存储类型时提供了最低限度的安全性,同时召回元素。但是这个解决方案需要rti,并且不是在所有平台上都可用。
#include <map>
#include <iostream>
#include <typeinfo>
class ResourcePointerStorage
{
private:
std::map< const std::string, std::pair<void*, const std::type_info*>> storage;
public:
bool Get(const std::string& id, std::pair<void*, const std::type_info*>& ptr )
{
auto it= storage.find( id );
if ( it==storage.end() ) return false;
ptr= it->second;
return true;
}
bool Put( const std::string& id, void* ptr, const std::type_info* ti)
{
storage[id]=make_pair(ptr, ti);
}
};
template < typename T>
bool Get(ResourcePointerStorage& rm, const std::string& id, T** ptr)
{
std::pair<void*, const std::type_info*> p;
if ( rm.Get( id,p ))
{
if ( *p.second != typeid(T)) { return false; }
*ptr= static_cast<T*>(p.first);
return true;
}
else
{
return 0;
}
}
template < typename T>
void Put( ResourcePointerStorage& rm, const std::string& id, T *ptr)
{
rm.Put( id, ptr, &typeid(T) );
}
class Car
{
private:
int i;
public:
Car(int _i):i(_i){}
void Print() { std::cout << "A car " << i << std::endl; }
};
class Animal
{
private:
double d;
public:
Animal( double _d):d(_d) {}
void Show() { std::cout << "An animal " << d << std::endl; }
};
int main()
{
ResourcePointerStorage store;
Put( store, "A1", new Animal(1.1) );
Put( store, "A2", new Animal(2.2) );
Put( store, "C1", new Car(3) );
Animal *an;
Car *car;
if ( Get(store, "A1", &an)) { an->Show(); } else { std::cout << "Error" << std::endl; }
if ( Get(store, "A2", &an)) { an->Show(); } else { std::cout << "Error" << std::endl; }
if ( Get(store, "C1", &car)) { car->Print(); } else { std::cout << "Error" << std::endl; }
// not stored object
if ( Get(store, "XX", &an)) { } else { std::cout << "Expected false condition" << std::endl; }
// false type
if ( Get(store, "A1", &car)) { } else { std::cout << "Expected false condition" << std::endl; }
};
我已经找到解决问题的方法了。我创建了一个宏:
#define convert(type, func) dynamic_cast<type>(func)
非常泛型和代码中立,允许从函数的返回类型动态转换类型。它还允许执行检查:
if (!convert(ShaderProgram*, rm::get("skyboxShader")))
cerr << "Conversion unsuccessful!" << endl;
else cout << "Conversion successful!" << endl;
我希望我的解决方案能帮助那些搜索类似问题的人。感谢所有!
- 如何使用Rcpp将R函数转换为C++函数
- C++函数转换为 C# 函数
- 将 C 函数转换为 C++ 以检查数字是否有效
- C++:从重载函数转换为 std::function
- 将 C 函数转换为C++语言
- C++隐式构造函数转换,后跟类型向上转换
- 将 lambda 函数转换为具有混合 lambda 引入器和参数列表的函子结构
- 通过 Boost Python 将 Python 函数转换为 C++,用作回调
- 如何将 MATLAB 图像处理库内置函数转换为 MATLAB 编码器代码生成不支持的 C++?
- 如何将函数转换为 lambda 函数
- 自定义函数转换错误?
- 将 C# 哈希函数转换为C++
- 将 lambda 函数转换为另一个编译单元中的普通函数会缩短编译时间吗?
- 加快 R 性能或将 R 函数转换为C++函数
- 将成员函数转换为指向成员函数的指针
- 将MATLAB炒作函数转换为C
- Rcpp - 用二进制函数转换数字向量?
- C lambda函数转换误差
- 此语法中的构造函数转换错误
- 将函数转换为find_if lambda