STL集中的指针委托
我有点坚持使用带有指针委托的集合。我的代码如下:
void Graph::addNodes (NodeSet& nodes)
{
for (NodeSet::iterator pos = nodes.begin(); pos != nodes.end(); ++pos)
{
addNode(*pos);
}
}
这里 NodeSet 定义为:
typedef std::set<Node_ptr, Node_ptr_Sorting_Predicate> NodeSet;
上面的代码在我的 Windows 机器上完美运行,但是当我在 MAC 上运行相同的代码时,它给出了以下错误:
没有调用“
Graph::addNode(const boost::shared_ptr
”的匹配函数&)
仅供参考,Node_ptr 的类型为:typedef boost::shared_ptr
有人可以告诉我为什么会发生这种情况吗?
I'm kinda stuck with using a set with a pointer delegate. My code is as follows:
void Graph::addNodes (NodeSet& nodes)
{
for (NodeSet::iterator pos = nodes.begin(); pos != nodes.end(); ++pos)
{
addNode(*pos);
}
}
Here NodeSet is defined as:
typedef std::set<Node_ptr, Node_ptr_Sorting_Predicate> NodeSet;
The above piece of code works perfectly on my windows machine, but when I run the same piece of code on a MAC, it gives me the following error:
no matching function for call to '
Graph::addNode(const boost::shared_ptr<Node>&)
'
FYI, Node_ptr is of type: typedef boost::shared_ptr<Node> Node_ptr;
Can somebody please tell me why this is happening?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
好的,从您添加的信息来看,问题似乎是
addNode
每个非const
引用采用一个Node_ptr
,而编译器必须调用该函数是一个const boost::shared_ptr&
(注意const
)。让我解释一下:std::set
是一个关联容器。关联容器以某种顺序存储其元素,使用键元素来定义顺序。如果您被允许在容器不知情的情况下更改密钥,那么您将使容器的内部顺序无效。这就是为什么我相信取消引用std::set::iterator
不会返回可修改的左值。 (这意味着您无法更改返回的引用。例如,如果您有一个迭代器pos
为std::set
,则*pos=42
不应编译。)这样做的问题是,只有可修改的左值才会绑定到非 const 引用。但是
*pos
返回的不是可修改的左值,因此不会。 (因此,在我的示例中,int& r = *pos;
不会编译。)原因是,如果允许这样做,您可以通过该非更改排序键const
在容器背后引用并打乱容器的内部顺序。这就是为什么
*pos
的结果不会绑定到Node_ptr&
的原因。这就是编译器无法调用您的函数的原因。你的
addNode()
成员函数真的改变了它给定的 Node 吗?如果不是,则应采用const Node_ptr&
。如果是这样,则说明存在设计问题。您无法更改集合中的元素。您唯一能做的就是从集合中删除它,更改它,然后将其添加回来。
附带说明:VC9 确实编译了以下代码:
我相信这是 VC9 中的错误。 Comeau 拒绝它。
以下是如何解决编译器不调用您认为应该调用的函数或从一组重载中调用错误函数的难题。
您认为应该调用的函数是 Graph::addNode(Node_ptr&)。您认为应该调用它的代码是
更改该代码,以便它提供所需的确切参数:
现在该调用肯定应该编译(或调用正确的重载),并且如果编译器认为
* 则应该吠叫pos
无法分配给Node_ptr&
。通常这种策略可以帮助我在这种情况下找出问题所在。
Ok, from your added information, the problem seems to be that
addNode
takes aNode_ptr
per non-const
reference, while what the compiler has to call the function is aconst boost::shared_ptr<Node>&
(note theconst
). Let me explain:std::set
is an associative container. Associative containers store their elements in some order, using the key element to define the ordering. If you would be allowed to change the key without the container knowing, you would invalidate the container's internal order. That's why I believe dereferencing astd::set<T>::iterator
does not return an modifiable lvalue. (Which means you cannot alter the reference returned. For example, if you have an iteratorpos
into astd::set<int>
,*pos=42
should not compile.)The catch with this is that only modifiable lvalues will bind to a non-
const
reference. But what*pos
returns isn't a modifiable lvalue and thus won't. (So, in my example,int& r = *pos;
won't compile.) The reason is that, if this was allowed, you could change the sorting key through that non-const
reference behind the container's back and mess up the container's internal ordering.That is why the result of your
*pos
won't bind to aNode_ptr&
. And that in turn is why the compiler cannot call your function.Does your
addNode()
member function really alter the Node it's given? If not, it should take aconst Node_ptr&
.If it does, you have a design problem. You cannot alter an element that's in a set. The only thing you can do is to remove it from the set, change it, and add it back in.
On a side note: VC9 indeed compiles the following piece of code:
I believe this is an error in VC9. Comeau rejects it.
Here's how to solve riddles with a compiler not calling a function you think it should call or calling the wrong function from a set of overloads.
The function you thought it should call is
Graph::addNode(Node_ptr&)
. The code that you thought should call it isChange that code so that it provides the exact parameter(s) required:
Now the call should definitely compile (or call the right overload), and the compiler should bark if it thinks
*pos
cannot be assigned to to aNode_ptr&
.Usually this tactic helps me to find out what's wrong in such situations.
如果没记错的话,原始 C++ 规范 (1998) 允许 std::set 返回可修改的迭代器。这带来了风险——迭代器可能被用来修改存储的值,从而导致集合的顺序被破坏。我相信规范的后续版本已经改变了这一点,现在所有设置迭代器都是不可修改的。
VC++ 2010 尊重新行为,并且具有不可修改的集合迭代器(这很烦人,因为它阻止进行不改变顺序且应该合法的更改)。
然而,之前的版本没有。这意味着您可以创建未使用 const 进行适当注释的函数,这将导致切换到不同编译器时出现问题。解决方案是添加必要的 const 更改。 VC++ 仍然可以工作(因为非常量值无论如何都可以隐式地变为 const),其他一切也都可以。
If memory serves, the original C++ spec (1998) permits std::set to return modifiable iterators. This carries with it a risk--the iterator might be used to modify the stored value, such that the ordering of the set is now broken. I believe subsequent versions of the spec have changed this, and now all set iterators are non-modifiable.
VC++ 2010 respects the new behaviour, and has non-modifiable set iterators (which is annoying, as it prevents making changes that don't change the ordering and which ought to be legal).
Prior versions, however, did not. This means that you can create functions that are not suitably annotated with const, which will cause problems on switching to different compilers. The solution is to add the necessary const changes. VC++ will still work (since non-const values can be implicitly made const anyway), and so will everything else.