从方法返回变量类型

Return variant type from method

本文关键字:类型 变量 返回 方法      更新时间:2023-10-16

所以我有一个资源管理器,它基本上是一个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::任何类型的对象,但它有点复杂(不是我懒惰)。我试图避免最终用户的模板语法。

任何帮助都太好了。此外,我不能使用Boost库结构,如变体或任何(项目规范)。提前感谢!

我知道我在这里有点要求魔法,但我认为这就是S/O的目的:寻找魔法。如果不可能,我能理解。但如果有人有创新的解决方案,那就太棒了。

除了其他答案之外,您还可以这样做,假设每个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)。所以这是一个专门的解决方案,但它可能是有用的,这取决于事情是如何结构化的(我真的不能知道没有看到更多的代码)。

EDIT:根据下面的注释,对象的类型似乎是由客户端在插入对象时确定的,所以您可能会这样做:

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来键入erase,那么他们将负责正确地恢复类型信息,要么在检索之前向下转换键,要么在检索之后向下转换资源。

请注意,这只是你必须做的事情之上的一个额外选项:如果你想使用非特定类型的键来提供对资源的访问,那么唯一的方法就是返回一个非特定的资源类型(即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版本基本上是你需要做的,没有这些模板重载,但其他两个版本是额外的选项,你可以使用这种方法而不需要任何运行时成本。

恐怕那样会太暧昧了。不能通过返回类型重载,也不能使用auto作为返回类型

我认为,最好的选择将是返回一些基类指针。缺点是你强迫任何人从它派生,但是基类的智能架构可以有更多的优点