我有一个这样的课程:
template<class T>
class AdjacencyList {
public:
void delete_node(const T&);
protected:
const typename std::vector<T>::const_iterator _iterator_for_node(
const std::vector<T>&, const T&
);
};
template<class T>
void AdjacencyList<T>::delete_node(const T& node) {
_nodes.erase(_iterator_for_node(_nodes, node));
}
template<class T>
const typename std::vector<T>::const_iterator AdjacencyList<T>::_iterator_for_node(
const std::vector<T>& list, const T& node
) {
typename std::vector<T>::const_iterator iter =
std::find(list.begin(), list.end(), node);
if (iter != list.end())
return iter;
throw NoSuchNodeException();
}
显然,std::vector::erase()
无法使用const_iterator
,但std::find()
需要一个const
。在将std::find()
提供给std::vector::erase()
时,我可以抛弃const_cast
返回的迭代器的{{1}} - 但Effective C++教会我怀疑{{1}}。
还有其他办法吗?我无法相信从向量中移除元素这一常见的东西应该需要类型体操。 :)
答案 0 :(得分:7)
我建议您更改或重载_iterator_for_node()
函数以接受对列表的非const引用。 std::find
返回const_iterator
的原因是因为列表本身为const
,因此begin()
和end()
返回const_iterator
。
另外,const_cast<>
实际上不会将const_iterator
转换为iterator
,因为'const'只是名称的一部分,而不是CV限定符。
此外,从技术上讲,您不应该使用下划线为名称添加前缀,因为这是为实现保留的。 (它通常会在实践中发挥作用)
答案 1 :(得分:5)
除了my direct modification of the code之外,还有一个想法:
而不是成员函数_iterator_for_node
我建议改为创建以下静态(全局/命名空间)函数:
template<class It, class T>
It checked_find(It begin, It end, const T& node)
{
It iter = std::find(begin, end, node);
if (iter != end)
return iter;
throw NoSuchNodeException();
}
它将适用于任何迭代器类型(包括非STL,输入流迭代器,仅转发,const,反向迭代器......你的名字)并且它不需要明确区分const /非const版本:)
您的代码示例的工作版本只需阅读
template<class T>
class AdjacencyList {
std::vector<T> _nodes;
public:
void delete_node(const T& node)
{ _nodes.erase(checked_find(_nodes.begin(), _nodes.end(), node)); }
};
请注意代码缩减。总是好兆头
干杯
答案 2 :(得分:1)
const元素和代码中的const迭代器之间似乎存在很多混淆。
在没有查看用例的情况下,我建议使用以下'修复'来编译:
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
struct NoSuchNodeException {};
template<class T>
class AdjacencyList {
std::vector<T> _nodes;
public:
void delete_node(const T&);
protected:
typename std::vector<T>::iterator _iterator_for_node(std::vector<T>&, const T&);
typename std::vector<T>::const_iterator _iterator_for_node(const std::vector<T>&, const T&) const;
};
template<class T>
void AdjacencyList<T>::delete_node(const T& node) {
_nodes.erase(_iterator_for_node(_nodes, node));
}
template<class T>
typename std::vector<T>::iterator AdjacencyList<T>::_iterator_for_node(std::vector<T>& list, const T& node)
{
typename std::vector<T>::iterator iter = std::find(list.begin(), list.end(), node);
if (iter != list.end())
return iter;
throw NoSuchNodeException();
}
template<class T>
typename std::vector<T>::const_iterator AdjacencyList<T>::_iterator_for_node(const std::vector<T>& list, const T& node) const
{
typename std::vector<T>::const_iterator iter = std::find(list.begin(), list.end(), node);
if (iter != list.end())
return iter;
throw NoSuchNodeException();
}
int main()
{
AdjacencyList<int> test;
test.delete_node(5);
}