我有一个字典集合(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>'
这当然是完全有道理的。 但是实现此功能的正确方法是什么? 我想我在这里实现的是某种工厂。
答案 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提供可以执行您想要的异构集。