3

マップのキーをセットの値と比較することで、includesアルゴリズムを動作させようとしています。回避する必要がある問題はもちろん、それはwhileであるため、両方の引数に同じ値の型を期待するデフォルトでは機能しません。setmapmap<K,V>::value_typepair<K,V>set<V>::value_typeVincludes predicate<T>

したがって、これを回避するために以下の述語クラスを書いています

template <class P,class K>
struct mapKey_set_less : public std::binary_function<P,K,bool>
{
   inline bool operator() (const P& x, const K& y) const {return x.first < y ;};
};

template <class K,class P>
struct set_mapKey_less : public std::binary_function<K,P,bool>
{
    inline bool operator() (const K& x, const P& y) const {return x < y.first ;};
};

ただし、VS2008 xutility ファイルの 313 行目でテンプレート インスタンシエーターがスローされます。

if (!_Pred(_Left, _Right))

const Vパラメータ1をからに変換できないというメッセージが表示されますconst std::pair<_Ty1,_Ty2>

これは、ファイルの 3795 行目で発生しているようです。

if (_DEBUG_LT_PRED(_Pred, *_First2, *_First1))

最初と 2 番目の引数が交換されているように見えるリリース構成でコンパイルすると、3795 行目で同じエラーが発生するため、Visual Studio の実装では、スイッチ (存在する場合) をいじらない限り、このコードを実行する必要があるようです。 _DEBUG_LT_PRED' マクロ。

私の質問は次のとおりです。これは Visual Studio のバグですか、それともこのような理由があり、間違いを犯していますか? 私は 10 年以上 C++ を使っていませんでしたが、先週いくつかのタイトなループで速度を上げるために取り直さなければならなかったので、私が得ることができるすべての助けが必要です。

皆さんありがとう

良い、

アルゴリズムの要件については考えていませんでした。両側から「未満」をチェックする必要があるのは理にかなっています。

ただし、これをコンパイルするのはあまり楽しいことではありません。

私の以前のコードで

template <class P,class K>
struct mapKey_set_cmp //: public std::binary_function<P,K,bool>
{
    inline bool operator() (const P& x, const K& y) const {return x.first < y ;};
};

私は得ていた

error C2664: 'bool mapKey_set_cmp<P,K>::operator ()(const P &,const K &) const' : 
cannot convert parameter 1 from 'const double' to 'const std::pair<_Ty1,_Ty2> &'

第 1 引数として double を取ることができる operator() がないため、これは理にかなっています。

追加のオーバーロードされた operator() を使用

template <class P,class K>
struct mapKey_set_cmp //: public std::binary_function<P,K,bool>
{
    inline bool operator() (const P& x, const K& y) const {return x.first < y ;};
    inline bool operator() (const K& x, const P& y) const {return x < y.first ;};
};

私は今得ています

error C2664: 'bool mapKey_set_cmp<P,K>::operator ()(const K &,const P &) const' : 
cannot convert parameter 1 from 'const std::pair<_Ty1,_Ty2>' to 'const double &'

error C2664: 'bool mapKey_set_cmp<P,K>::operator ()(const K &,const P &) const' : 
cannot convert parameter 1 from 'const std::pair<_Ty1,_Ty2>' to 'const double &'

error C2664: 'bool mapKey_set_cmp<P,K>::operator ()(const K &,const P &) const' : 
cannot convert parameter 2 from 'const double' to 'const std::pair<_Ty1,_Ty2> &'

error C2664: 'bool mapKey_set_cmp<P,K>::operator ()(const K &,const P &) const' : 
cannot convert parameter 2 from 'const double' to 'const std::pair<_Ty1,_Ty2> &'

注目すべきは、すべてのエラーが 2 番目operator()K1 番目とP2 番目のものを参照しているように見えることです。そして、はい、言及されている変換はどれも、その演算子では可能であってはなりません。しかし、なぜコンパイラは他の演算子を試さないのでしょうか? つまり、それらの変換が許可されるべきものです。(ところで、疑問に思っている場合に備えて、エラーはそれぞれ2つの異なる行で発生するため、繰り返されます)

これが考えられるもう1つのことは、もちろんconstの不正確さです。長くなりましたので、じっくり考えてみたいと思います。

助けてくれてありがとう

2013 年 5 月 15 日に編集

私は「それをやり遂げる」必要があったので、includes2 つのセットでアルゴを呼び出すことができるように、マップ キーをセットに入れることでこの問題を回避しました (明らかなパフォーマンス ペナルティが発生しました)。私はまだこれを適切に解決したいと思っています。Visual Studio 2008 で説明しているコンパイラ エラーを再現するために必要なすべてのコードを次に示します。

template <class PAIR,class KEY>
struct mapKey_set_less : public std::binary_function<PAIR,KEY,bool>
{
    inline bool operator() (const PAIR& x, const KEY& y) const {return x.first < y ;};
    inline bool operator() (const KEY& x, const PAIR& y) const {return x < y.first ;};
};

int _tmain(int argc, _TCHAR* argv[])
{
    map<string,double> theMap;
    theMap["arse"] = 1;

    set<string> theSet;
    theSet.insert("arse");

    typedef map<string,double>::iterator MI;
    MI mi(theMap.begin()), miend(theMap.end());

    typedef set<string>::iterator SI;
    SI si(theSet.begin()), siend(theSet.end());

    typedef mapKey_set_less< pair<string,double>,string> cmp;

    if (includes(mi,miend,si,siend,cmp()))
    {}

}

コンパイラが吐き出す

Error   1   error C2664: 'bool mapKey_set_less<PAIR,KEY>::operator ()(const KEY &,const PAIR &) const' : cannot convert parameter 1 from 'std::pair<_Ty1,_Ty2>' to 'const std::string &'    c:\program files (x86)\microsoft visual studio 9.0\vc\include\xutility  346
Error   2   error C2664: 'bool mapKey_set_less<PAIR,KEY>::operator ()(const KEY &,const PAIR &) const' : cannot convert parameter 1 from 'std::pair<_Ty1,_Ty2>' to 'const std::string &'    c:\program files (x86)\microsoft visual studio 9.0\vc\include\xutility  348
Error   3   error C2664: 'bool mapKey_set_less<PAIR,KEY>::operator ()(const KEY &,const PAIR &) const' : cannot convert parameter 2 from 'std::basic_string<_Elem,_Traits,_Ax>' to 'const std::pair<_Ty1,_Ty2> &'   c:\program files (x86)\microsoft visual studio 9.0\vc\include\xutility  346
Error   4   error C2664: 'bool mapKey_set_less<PAIR,KEY>::operator ()(const KEY &,const PAIR &) const' : cannot convert parameter 2 from 'std::basic_string<_Elem,_Traits,_Ax>' to 'const std::pair<_Ty1,_Ty2> &'   c:\program files (x86)\microsoft visual studio 9.0\vc\include\xutility  348

最初のエラーだけを見ると、operator()(KEY,PAIR) を使用して PAIR,KEY を渡したいようです。利用可能な operator()(PAIR,KEY) を無視するのはなぜですか??? 他のエラーはすべて同じ傾向にあります。コンパイラは、完全に適切なオーバーロードされた演算子を無視するように「見えます」

助けてくれてありがとう

4

1 に答える 1

2

最初の範囲のオブジェクトは比較関数の左側の引数としてのみ渡され、2 番目の範囲のオブジェクトは右側の引数としてのみ渡されるという規格の要件はありません。したがって、Visual Studio が行っていることは完全に有効であり、多くの場合必要です (以下を参照)。

できることは、両方のケースを処理する単一のファンクターを作成することです。

template <class K,class P>
struct set_mapKey_less : public std::binary_function<K,P,bool>
{
    inline bool operator() (const K& x, const P& y) const {return x < y.first;};
    inline bool operator() (const P& y, const K& x) const {return y.first < x; }
};
...
std::map<int,int> m;
std::set<int> s;

std::includes(m.begin(), m.end(), s.begin(), s.end(),
              set_mapKey_less<int,std::pair<int const,int> >());

VS が行っているチェックが必要な理由を理解するには、次の点を考慮してください。

set X = { 1000, 3000, 5000, 7000, 9000 }
map Y = { (3000,'a') }

左側にペアの値、右側に整数を取る小なり演算子しかない場合、X に Y が含まれているかどうかをどのようにテストしますか?

Is (3000,'a').first < 1000? No.
Is (3000,'a').first < 3000? No.
Is (3000,'a').first < 5000? Yes.

この時点で、(3000,'a').firstがセット内にある場合、 が 3000 でなければならないことがわかります。しかし、左辺のペアしか取ることができない比較器を使用して、それが実際に 3000 であることをどのようにテストすればよいでしょうか? 引数を逆にすることができれば、それを行うことができます。

Is 3000 < (3000,'a').first? No.

これで、は 未満ではなく、3000未満ではないことがわかりました。したがって、これらは等しくなければなりません。(3000,'a').first(3000,'a').first3000

于 2013-02-07T01:47:00.800 に答える