所以我有以下STL std::map
容器
#include <map>
#include <vector>
// ...
class Type
{
std::string key;
int support;
};
std::map<Type, std::vector<int> > index;
我想重载地图,因此下面的两个if子句都可以工作:
int main()
{
std::map<Type, std::vector<int> > index;
Type type1;
type1.key = "test";
type1.support = 10;
index[type1] = std::vector<int>();
if (index.find(type1) != index.end())
{
index[type1].push_back(0);
}
// I can not make this work
if (index.find("test") != index.end())
{
index["test"].push_back(0);
}
return 0;
}
我尝试了这些重载:
class Type
{
public:
std::string key;
int support;
size_t operator()() const
{
return std::hash<std::string>{}(name);
}
bool operator==(const struct Type& obj) const
{
return (key == obj.key);
}
bool operator<(const struct Type& obj) const
{
return key < obj.key;
}
bool operator<(const std::string& other_key) const
{
return key < other_key;
}
bool operator==(const std::string& other_key) const
{
return other_key == key;
}
};
namespace std
{
template<>
struct hash<Type>
{
size_t operator()(const Type& obj) const
{
return obj();
}
// Specialization here does not seem to work
size_t operator()(const std::string& name) const
{
return std::hash<std::string>{}(name);
}
};
template<>
struct less<Type>
{
bool operator() (const std::string& lname, const std::string& rname)
{
return lname < rname;
}
};
因为在我的模型中,std::string key
字段唯一地定义了Type,所以我如何重载std::map
容器,以便可以对容器的项目进行索引?我可以在C ++中做到吗?
PS:我知道某些代码在重载中可能是多余的
答案 0 :(得分:7)
从C ++ 14开始,您需要的被称为异构查找,并且受std::map
支持。为此,您可以定义自己的比较器结构并在其中提供类型is_transparent
以启用此功能。有关如何启用异构查询的详细信息,请参见How can I search an std::map using a key of a different type
还请注意,尽管std::map::find()
确实支持std::map::operator[]
,所以您必须替换代码:
if (index.find("test") != index.end())
{
index["test"].push_back(0);
}
类似于:
auto it = index.find("test");
if( it != index.end())
it->second.push_back(0);
无论如何,您都应该这样做,因为您将执行两次查找而不是一次查找,这在地图上的操作非常昂贵。
所以对于您的情况,比较器应类似于:
struct CompareType
{
using is_transparent = std::true_type;
// standard comparison (between two instances of Type)
bool operator()(const Type& lhs, const Type& rhs) const { return lhs.key < rhs.key; }
// comparisons btw Type and std::string
bool operator()( const Type& lhs, const std::string &rhs) const { return lhs.key < rhs; }
bool operator()(const std::string &lhs, const Type& rhs) const { return lhs < rhs.key; }
};
然后您通过以下方式创建地图:
std::map<Type, std::vector<int>,CompareType> index;
并且您不再需要Type
本身中的比较方法
另一种方法是将std::less<>
作为第三个参数提交给std::map
,但是在这种情况下,您缺少比较运算符,该运算符将std::string
作为左操作数,而将Type
正确,并且该比较运算符不能成为Type
的成员,我认为通过单独的比较器(代码一致)比较干净。
答案 1 :(得分:0)
只需尝试以下方法:
std::map<Type, std::vector<int>, std::less<> > index;
这需要C ++ 14。请注意,使用没有模板参数的std::less
可以搜索“兼容”键,而不仅仅是精确的key_type
。这就是您需要通过自定义比较功能来“解锁” find()
的使用。
std::map
的默认第三个模板参数为std::less<key_type>
,这是受限制的。为了与C ++ 14之前的代码向后兼容,仍然使用这种方法,但是如果没有模板参数就可以使用std::less
来完成许多新代码。
答案 2 :(得分:0)
我在提供的代码中看到两个问题:
map::find()
和map::operator[]
的参数。编译器无法从const char *转换为Type。首先,满足Type作为std :: map <>:
的键类型的要求// Define comparison/ordering of two Type instances
bool operator<(const Type& a, const Type& b)
{
return a.key < b.key;
}
第二,定义如何使用single-arg ctor将const char *(例如“ test”)隐式转换为Type:
class Type
{
public:
// Implicitly converts const char* value to instance of Type.
Type(const char* k) : key(k), support(0) {}
//...
};
这不需要任何更新的(C ++ 11或C ++ 14)语言功能。