所以我有一个资源管理器,它基本上是一个void *对象的字典,它有一些描述其类型的元数据(像字符串这样的基本元数据)。我现在有一个模板方法返回一个对象:
class ResourceManager
{
template<typename Type>
Type RetrieveResource( Text name );
};
我的问题是如何使这个方法不模板方法?我已经对尾随返回类型和使用那种时髦的语法做了一些研究。我的想法是,在某些时候我将数据作为正确的类型,并且我希望将其作为该类型返回,而不在最终用户的部分进行额外的转换。
我正在拍摄这样的事情:
auto RetrieveResource( Text name)
{
return _dictionary[ name ]; // There's more to this, but imagine it returns varying type objects.
}
我已经考虑过实现一个Boost :: Any类型的对象,但它有点复杂(不是我很懒)。我试图避免最终用户的模板语法。
任何帮助都会很棒。此外,我不能使用像变体或任何(项目规范)的Boost库结构。提前谢谢!
我知道我在这里要求魔法,但我认为这就是S / O的用途:找到魔法。如果不可能,我理解。但如果有人有创新的解决方案,那就太棒了。
答案 0 :(得分:1)
除了其他答案之外,您可以执行类似的操作,假设每个Text
键唯一对应于具有已知,不同Type
的资源:
class BaseText
{
// constructors that take const char *, std::string, etc.
// .. whatever else you currently have in class Text
};
template<typename Type>
class Text : public BaseText
{
// constructors that take const char *, std::string, etc.
};
然后将ResourceManager
更改为:
class ResourceManager
{
template<typename Type>
Type RetrieveResource( Text<Type> name );
};
请注意,这仍然需要编译时多态,但意味着只要您的用户可以获得正确类型的Text<Type>
版本,他们就可以使用它来获取正确类型的资源,而无需显式提供再次Type
参数,所以它看起来像一个普通的函数调用。
如果可以使用正确的类型静态声明和初始化可能的Text<Type>
对象集合,这很容易。在我的情况下,我不确定是否属实。但是,如果用户必须能够在运行时创建它们,那么他们需要知道要创建的正确类型,因此它只是将问题推迟了一些:但是,如果用户可能会很方便相同的Text<Type>
对象将被反复使用。
请注意,如果您或客户需要在某种数据结构中将不同的Text<Type>
对象存储在一起,那么您也会运气不好,因为这需要某种类型的擦除(即向上转换为BaseText
)。所以这有点像一个专门的解决方案,但它可能是有用的,这取决于事物的结构(我真的不知道你能看到更多的代码)。
编辑:根据下面的评论,似乎客户在插入对象时确定了对象的类型,因此您可以执行以下操作:
class ResourceManager
{
BaseText PutResource( const BaseText& name, BaseResource& resource );
template<typename Type>
Text<Type> PutResource( const BaseText& name, Type& resource );
BaseResource& RetrieveResource( const BaseText& name );
template<typename Type>
Type& RetrieveResource( const Text<Type>& name );
};
因此,客户端需要保留唯一键入的键对象,以便稍后检索资源;如果他们选择通过向上转换回BaseText
来键入擦除它,那么他们将负责正确地恢复类型信息,或者通过在检索之前向下转换密钥或者之后向下转发资源。
请注意,这只是一个额外的选项,除了你必须要做的事情之外:如果你想使用非类型特定的密钥提供对资源的访问,唯一的方法是返回一个非 - 特定资源类型(即BaseResource
,boost::any
,boost::variant<...>
或其中一个道德等价物。)但是,创建特定于类型的子类BaseText
可以获得正确类型的资源,使用完全相同的语法(即不需要显式模板参数)。此外,这允许以下用法:
// tree is a resource of type `Tree`
auto key = manager.PutResource("Tree01", tree);
// ...
const BaseText& basekey = key; // lose type information
// ...
// these are all equivalent
Tree& tree = dynamic_cast<Tree&>(manager.RetrieveResource("Tree01"));
Tree& tree = dynamic_cast<Tree&>(manager.RetrieveResource(basekey));
Tree& tree = manager.RetrieveResource(key); // no casts required
Tree& tree = manager.RetrieveResource<Tree>("Tree01")
dynamic_cast
版本基本上是您在没有这些模板化重载的情况下需要做的事情,但其他两个版本是额外的选项,您可以使用此方法而无需任何运行时成本。
答案 1 :(得分:0)
我担心这会是模棱两可的。您can't overload by return type并且您无法使用auto
作为返回类型。
答案 2 :(得分:0)
我认为,最好的选择是返回一些基类指针。减号是你强迫任何人从中衍生出来,但是基类的智能架构可能会有更多的优势