有没有办法重命名地图迭代器的第一个和第二个访问器函数。我知道他们有这些名称是因为代表键和值的底层对,但我希望迭代器更具可读性。我认为这可能是使用迭代器适配器,但我不知道如何实现它。
请注意,我不能使用提升。
我的意思是:
map<Vertex, Edge> adjacency_list;
for(map<Vertex, Edge>::iterator it = adjacency_list.begin();
it != adjacency_list.end();
++it)
{
Vertex v = it->first;
//instead I would like to have it->vertex
}
答案 0 :(得分:18)
如果您只关心可读性,可以这样做:
typedef map<Vertex, Edge> AdjacencyList;
struct adjacency
{
adjacency(AdjacencyList::iterator& it)
: vertex(it->first), edge(it->second) {}
Vertex& vertex;
Edge& edge;
};
然后:
Vertex v = adjacency(it).vertex;
答案 1 :(得分:12)
您无法重命名成员,但可以使用某些功能来提供帮助。
inline Vertex& vertex(map<Vertex, Edge>::iterator& it) {return it->first;}
inline Edge& edge(map<Vertex, Edge>::iterator& it) {return it->second;}
然后,您可以执行it->vertex
vertex(it)
答案 2 :(得分:7)
不幸的是,没有。我通常做的是:
typedef map<Vertex, Edge> AdjacencyList;
typedef AdjacencyList::value_type Vertex_Edge_Pair;
为了便于阅读。在你的循环内你也可以说
Vertex& current_vertex = it->first;
Edge& current_edge = it->second;
答案 3 :(得分:6)
当然,重新实现或包装迭代器,但值得努力吗?不会
Vertex& v = it->first;
更容易吗?
答案 4 :(得分:1)
我不建议真正使用它,但它似乎确实有效,至少在测试程序的最低程度做我想要/期望的事情:
#include <map>
#include <string>
#include <iostream>
template <class T, class U>
struct my_pair : public std::pair<T, U> {
T const &vertex;
my_pair(std::pair<T, U> const &x) : std::pair<T, U>(x), vertex(x.first) { }
};
template <class T, class U>
struct my_map : public std::map<T, U> {
my_pair<T, U> find(T const &t) { return my_pair<T, U>(*std::map<T,U>::find(t)); }
};
class Vertex {
int x;
public:
Vertex(int v) : x(v) {}
bool operator<(Vertex const &other) const { return x < other.x; }
friend std::ostream &operator<<(std::ostream &os, Vertex const &v) { return os << v.x; }
};
int main() {
my_map<Vertex, std::string> m;
m[1] = "This is it";
my_pair<Vertex, std::string> mp = m.find(1);
std::cout << mp.vertex << ": " << mp.second;
return 0;
}
答案 5 :(得分:1)
我喜欢KeithB的免费功能解决方案。但是,更可重用的解决方案可能会很好。
首先访问第一个或第二个的函数对象怎么样,因为您可以根据需要命名实例:
#include <map>
#include <string>
#include <iostream>
struct GetFirst
{
template <class First, class Second>
First& operator()(std::pair<First, Second>& p)
{
return p.first;
}
template <class First, class Second>
const First& operator()(const std::pair<First, Second>& p)
{
return p.first;
}
};
struct GetSecond
{
template <class First, class Second>
Second& operator()(std::pair<First, Second>& p)
{
return p.second;
}
template <class First, class Second>
const Second& operator()(const std::pair<First, Second>& p)
{
return p.second;
}
};
int main()
{
typedef std::map<std::string, int> Map;
Map persons;
persons["John"] = 20;
persons["Mary"] = 24;
//create named accessors
GetFirst name;
GetSecond age;
for (Map::iterator it = persons.begin(); it != persons.end(); ++it) {
std::cout << name(*it) << " is aging.\n";
++age(*it);
}
for (Map::const_iterator it = persons.begin(); it != persons.end(); ++it) {
std::cout << "Name: " << name(*it) << ", age: " << age(*it) << '\n';
}
}
这是我能做的最好的事情。我也尝试让这些仿函数直接接受迭代器,但这种或那种方式意味着签名将包含依赖名称,这显然使模板类型推断不可能(我找不到为iterator/const_iterator
重载GetSecond的方法即使延迟返回类型为C ++ 0x)。
答案 6 :(得分:0)
我有一个邪恶的解决方案!
#define vertex first
#define edge second
虽然作为一种邪恶的解决方案,但是当你不小心在其他地方使用这些词时,它无疑会造成巨大的创伤并难以诊断编译问题。
添加完整性。
无法相信其他人没有这样做过。
答案 7 :(得分:0)
如果您不需要迭代器(例如,基于范围的for循环适合您的目的),那么从 c ++ 17 开始,您可以使用结构化绑定:
map<Vertex, Edge> adjacency_list;
for( auto & [ vertex, edge ] : adjacency_list )
{
// do stuff with vertex
}