交换机模板类型

Switch template type

本文关键字:类型 交换机      更新时间:2023-10-16

我想为我的游戏创造一些存储空间。现在代码看起来像:

class WorldSettings
{
    private:
        std::map<std::string, int> mIntegerStorage;
        std::map<std::string, float> mFloatStorage;
        std::map<std::string, std::string> mStringStorage;
    public:
        template <typename T>
        T Get(const std::string &key) const
        {
            // [?]
        }
};

所以,我有一些关联容器来存储数据的确切类型。现在我想在设置中添加一些值:settings.Push<int>("WorldSize", 1000);并得到它:settings.Get<int>("WorldSize");。但如何切换需要映射由于传递类型到模板?

或者,也许你知道一个更好的方法,谢谢。

如果你的编译器支持这个1,你可以使用模板函数特化:

class WorldSettings
{
    private:
        std::map<std::string, int> mIntegerStorage;
        std::map<std::string, float> mFloatStorage;
        std::map<std::string, std::string> mStringStorage;
    public:
        template <typename T>
        T Get(const std::string &key); // purposely left undefined
};
...
template<>
int WorldSettings::Get<int>(const std::string& key) {
    return mIntegerStorage[key];
}
template<>
float WorldSettings::Get<float>(const std::string& key) {
    return mFloatStorage[key];
}
// etc

注意方法不是const,因为map<>::operator[]不是const

同样,如果有人试图使用模板的类型不是你提供的特化类型,他们会得到链接器错误,所以你的代码不会出错或任何事情。


1如果没有,请参阅@gwiazdorrr的答案

首先,因为在c++ 11之前你不能专门化函数,你的成员函数必须在签名上不同——返回类型不算数。根据我在一些编译器上的经验,你可以不使用它,但像往常一样,你应该让你的代码尽可能接近标准。

也就是说,你可以添加一个不会影响性能和调用函数方式的虚拟参数:

public:
    template <typename T>
    T Get(const std::string &key) const
    {
        return GetInner(key, (T*)0);
    }
private:
    int GetInner(const std::string& key, int*) const
    {
        // return something from mIntegerStorage
    }
    float GetInner(const std::string& key, float*) const
    {
        // return something from mFloatStorage
    }

以此类推。

Seth的答案是理想的,但是如果您无法访问c++ 11编译器,那么您可以使用模板类专门化来代替。它更冗长,但保持相同的功能。

class WorldSettings
{
    template<class T>
    struct Selector;
    template<class T>
    friend struct Selector;
private:
    std::map<std::string, int> mIntegerStorage;
    std::map<std::string, float> mFloatStorage;
    std::map<std::string, std::string> mStringStorage;
public:
    template <typename T>
    T Get(const std::string &key)
    {
        return Selector<T>::Get(*this)[key];
    }
};
template<>
struct WorldSettings::Selector<int>
{
    static std::map<std::string, int> & Get(WorldSettings &settings)
    {
        return settings.mIntegerStorage;
    }
};
template<>
struct WorldSettings::Selector<float>
{
    static std::map<std::string, float> & Get(WorldSettings &settings)
    {
        return settings.mFloatStorage;
    }
};
// etc.

在c++ 03中,我建议在容器类型中使用' boost::any '。您需要一个访问器:

std::map<std::string,boost::any> storage;
template <typename T> getValue( std::string const & key ) {
   return boost::any_cast<T>( storage[key] );
}

这是一个粗略的草图,作为一个成员函数,它将是const,并且它应该使用' map::find '来在搜索时不修改容器,它应该处理无效的joy,并且可能将boost异常重新映射到您自己的应用程序异常中。