15

だから、私はstd :: map、lambda、stlアルゴリズム(remove_if)に問題があります。実際には、std::listまたはstd::vectorと同じコードが適切に機能します。

私のテスト例:

#include <map>
#include <iostream>
#include <algorithm>

struct Foo
{
    Foo() : _id(0) {}
    Foo(int id) : _id(id)
    {

    }

    int _id;    
};
typedef std::map<int, Foo> FooMap;


int main()
{
    FooMap m;
    for (int i = 0; i < 10; ++i)
        m[i + 100] = Foo(i);

    int removeId = 6;
    // <<< Error here >>>
    std::remove_if(m.begin(), m.end(), [=](const FooMap::value_type & item) { return item.second._id == removeId ;} ); 

    for (auto & item : m )
        std::cout << item.first << " = " << item.second._id << "\n";    

    return 0;
}

エラーメッセージ :

In file included from /usr/include/c++/4.6/utility:71:0,
                 from /usr/include/c++/4.6/algorithm:61,
                 from main.cxx:1:
/usr/include/c++/4.6/bits/stl_pair.h: In member function ‘std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(std::pair<_T1, _T2>&&) [with _T1 = const int, _T2 = Foo, std::pair<_T1, _T2> = std::pair<const int, Foo>]’:
/usr/include/c++/4.6/bits/stl_algo.h:1149:13:   instantiated from ‘_FIter std::remove_if(_FIter, _FIter, _Predicate) [with _FIter = std::_Rb_tree_iterator<std::pair<const int, Foo> >, _Predicate = main()::<lambda(const value_type&)>]’
main.cxx:33:114:   instantiated from here
/usr/include/c++/4.6/bits/stl_pair.h:156:2: error: assignment of read-only member ‘std::pair<const int, Foo>::first’

ここで何が悪いのかわかりません。それで、私はそれについてのいくつかのアドバイス/指示を読んでうれしく思います。私の目標-std::mapとremove_ifなどのアルゴリズムで新しいラムダスタイルを使用します。

g ++ 4.6、-std = c++0x。

4

2 に答える 2

30

問題はstd::map<K,V>::value_typestd::pair<const K, V>別名、割り当て可能で.firstはないということです。constラムダはここでの問題とは何の関係もありません。

std::remove_ifコンテナの要素を移動してアイテムを「削除」します。これにより、述語に適合しないものはすべて、返されるイテレータの前の前面に配置されます。その後のイテレータはすべて指定されていません。それは単純な割り当てでそれを行います、そしてあなたがconst変数に割り当てることができないので、あなたはそのエラーを受け取ります。†</sup>

名前removeは少し誤解を招く可能性があり、この場合、あなたは本当に欲しいerase_ifのですが、残念ながら、それは存在しません。すべてのアイテムを繰り返し処理し、次のコマンドを使用して手動で消去する必要がありますmap.erase(iterator)

for(auto it = map.begin(), ite = map.end(); it != ite;)
{
  if(it->second._id == remove_id)
    it = map.erase(it);
  else
    ++it;
}

他のイテレータが無効になることなくツリー内の個々のノードを消去できるため、これは安全です。ノードを消去した場合に要素をスキップするため、forループヘッダー自体のイテレーターをインクリメントしなかったことに注意してください。


†これまでに、これが'の順序に大混乱をもたらすことに気付いたはずですstd::map。これが、キーが-である理由constです。したがって、アイテムが挿入された後は、順序に影響を与えることはできません。

于 2012-03-01T11:35:16.183 に答える
3

マップの検索と消去を使用できます。remove_ifほど便利ではありませんが、これまでで最高の方法かもしれません。

int removeId = 6;
auto foundIter = m.find(removeId);

// if removeId is not found you will get an error when you try to erase m.end()
if(foundIter != m.end())
{
    m.erase(foundIter);
}
于 2013-12-11T17:06:06.203 に答える