从方法返回变体类型

时间:2013-03-19 17:42:57

标签: c++ templates trailing-return-type

所以我有一个资源管理器,它基本上是一个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的用途:找到魔法。如果不可能,我理解。但如果有人有创新的解决方案,那就太棒了。

3 个答案:

答案 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来键入擦除它,那么他们将负责正确地恢复类型信息,或者通过在检索之前向下转换密钥或者之后向下转发资源。

请注意,这只是一个额外的选项,除了你必须要做的事情之外:如果你想使用非类型特定的密钥提供对资源的访问,唯一的方法是返回一个非 - 特定资源类型(即BaseResourceboost::anyboost::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)

我认为,最好的选择是返回一些基类指针。减号是你强迫任何人从中衍生出来,但是基类的智能架构可能会有更多的优势