0

ポインターデリゲートを使用したセットの使用にちょっとこだわっています。私のコードは次のとおりです。

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>&)' ' の呼び出しに一致する関数がありません

参考までに、 Node_ptr のタイプは次のとおりです。typedef boost::shared_ptr<Node> Node_ptr;

なぜこれが起こっているのか誰か教えてもらえますか?

4

2 に答える 2

1

わかりました、追加された情報から、コンパイラが関数を呼び出さなければならないのに対し、非参照ごとに問題addNodeがあるようです(注意してください)。説明させてください:Node_ptrconstconst boost::shared_ptr<Node>&const

std::set連想コンテナです。連想コンテナは、キー要素を使用して順序を定義し、要素をある順序で格納します。コンテナが知らないうちにキーを変更できるようにすると、コンテナの内部順序が無効になります。std::set<T>::iteratorそのため、 a を逆参照しても変更可能な左辺値は返されないと私は考えています。(これは、返された参照を変更できないことを意味します。たとえば、イテレータposを aに持っている場合は、コンパイルしないstd::set<int>でください。) これのキャッチは、変更可能な左辺値のみが非参照 にバインドされることです。しかし、返されるものは変更可能な左辺値ではないため、変更されません。(したがって、私の例ではコンパイルされません。)その理由は、これが許可されている場合、その非 - を介してソートキーを変更できるからです。*pos=42
const*posint& r = *pos;constコンテナの背後にある参照を参照し、コンテナの内部順序を台無しにします。
そのため、 your *poswill の結果が a にバインドされませんNode_ptr&。そしてそれが、コンパイラが関数を呼び出せない理由です。

あなたのaddNode()メンバー関数は、与えられたノードを本当に変更しますか? そうでない場合は、const Node_ptr&.
もしそうなら、あなたは設計上の問題を抱えています。セット内の要素を変更することはできません。できることは、セットから削除して変更し、再度追加することだけです。

余談ですが、VC9 は実際に次のコードをコンパイルします。

#include <iostream>
#include <set>
#include <typeinfo>
#include <iterator>

int main()
{
    std::set<int> set;
    set.insert(5);
    std::cout << *set.begin() << '\n';
    *set.begin() = 3; // this is an error!
    std::cout << *set.begin() << '\n';
    return (0);
}

これは VC9 のエラーだと思います。コモーはそれを拒否します。


呼び出す必要があると思われる関数をコンパイラが呼び出さない、またはオーバーロードのセットから間違った関数を呼び出すという謎を解決する方法を次に示します。
あなたが呼び出すべきだと思った関数は ですGraph::addNode(Node_ptr&)。あなたがそれを呼び出すべきだと思ったコードは

addNode(*pos);

必要な正確なパラメーターを提供するようにそのコードを変更します。

Node_ptr& tmp = *pos;
addNode(tmp);

これで、呼び出しは確実にコンパイルされる (または正しいオーバーロードを呼び出す) ようになり、*posを に割り当てることができないとコンパイラが判断した場合、コンパイラは吠える必要がありNode_ptr&ます。
通常、この戦術は、そのような状況で何が問題なのかを見つけるのに役立ちます。

于 2010-05-17T21:46:05.277 に答える
0

メモリが機能する場合、元のC ++仕様(1998)では、std::setが変更可能なイテレータを返すことが許可されています。これにはリスクが伴います。イテレータを使用して、格納されている値を変更し、セットの順序が崩れる可能性があります。仕様の後続のバージョンでこれが変更されたと思います。現在、設定されているすべてのイテレータは変更できません。

VC ++ 2010は新しい動作を尊重し、変更不可能なセットイテレータを備えています(順序を変更せず、合法であるはずの変更を行わないため、煩わしいです)。

ただし、以前のバージョンはそうではありませんでした。これは、constで適切に注釈が付けられていない関数を作成できることを意味します。これにより、別のコンパイラに切り替えるときに問題が発生します。解決策は、必要なconstの変更を追加することです。VC ++は引き続き機能し(非const値は暗黙的にconstにすることができるため)、他のすべても機能します。

于 2010-05-18T09:01:49.993 に答える