从一组词典中返回通用容器

时间:2015-07-14 16:02:14

标签: c++ templates

我有一个字典集合(std :: maps),它们将通用容器Foo与唯一ID存储在一起。鉴于这样一个唯一的ID,我想返回相应的容器。但是我不知道在哪个dict中存储了具有给定ID的Foo对象,所以沿着以下几行:

#include <map>

std::map<ID, Foo<double>> mapDouble;
std::map<ID, Foo<int>>    mapInt;


template <class T>
Foo<T> getVal(ID id) {

    std::map<ID, Foo<double>>::iterator itDoub = mapDouble.find(id);
    if(itDoub != mapDouble.end()) {
       return = itDoub->second;
    }


    std::map<ID, Foo<int>>::iterator itInt = mapInt.find(id);
    if(itInt!= mapInt.end()) {
       return = itInt->second;
    }
}


void bar() {
    Foo<int> foo getVal<int>(3);
}

但是我收到以下错误消息

error: no viable conversion from 'Foo <double>' to 'Foo <int>'

这当然是完全有道理的。 但是实现此功能的正确方法是什么? 我想我在这里实现的是某种工厂。

1 个答案:

答案 0 :(得分:1)

您的问题是类型参数(<int>)和成员名称(mapInt)之间没有很好的连接。

解决方案是找到一些不使用该成员的方法 - 最简单的是:

#include <map>

typedef int ID;
template <typename T> struct Foo {};

class MapContainer {
    std::map<ID, Foo<double>> mapDouble;
    std::map<ID, Foo<int>>    mapInt;

    template <typename T> std::map<ID, Foo<T>>& getmap();

public:
    template <class T>
    Foo<T> getVal(ID id) {
        auto &map = getmap<T>();
        auto it = map.find(id);
        if(it != map.end()) {
            return it->second;
        } else {
            return Foo<T>{}; // ???
        }
    }
};

template <> std::map<ID, Foo<double>>& MapContainer::getmap() { return mapDouble; }
template <> std::map<ID, Foo<int>>& MapContainer::getmap() { return mapInt; }

此处,类型和成员名称之间的连接由模板方法特化(getmap)处理。

请注意,这会为不支持的类型提供链接器错误。您可以通过定义通用getmap使其在实例化时失败来获得稍微友好的错误消息。

一个小问题,但也许更令人满意的解决方案(也可以更好地扩展和推广到更多类型)是完全消除命名数据成员,并使用通用的类型到容器查找。例如,可以通过元素类型而不是位置来查询映射元组(请参阅Modern C ++ Design / Loki),Boost.Fusion提供可以执行您想要的异构集。