wake-up-neo.com

Verwendung von for_each auf Kartenelementen

Ich habe eine Karte, auf der ich jeden Objekttyp des Datentyps aufrufen möchte. Ich weiß zwar noch, wie man dies in einer beliebigen Reihenfolge macht, aber ist es möglich, dies in einem assoziativen Container durchzuführen?

Die beste Antwort, die ich finden konnte, war folgende: Boost.Bind, um auf std :: map-Elemente in std :: for_each zuzugreifen. Aber ich kann boost in meinem Projekt nicht verwenden. Gibt es eine STL-Alternative, die mir fehlt, um :: bind :: bind?

Wenn dies nicht möglich ist, habe ich daran gedacht, eine temporäre Sequenz für Zeiger auf die Datenobjekte zu erstellen und dann for_each aufzurufen, etwa wie folgt:

class MyClass
{
public:
 void Method() const;
}

std::map<int, MyClass> Map;
//...

std::vector<MyClass*> Vector;
std::transform(Map.begin(), Map.end(), std::back_inserter(Vector), std::mem_fun_ref(&std::map<int, MyClass>::value_type::second));
std::for_each(Vector.begin(), Vector.end(), std::mem_fun(&MyClass::Method));

Es sieht zu verschmiert aus und ich mag es nicht wirklich. Irgendwelche Vorschläge?

37
Antonio Pérez

Sie können ein std::map-Objekt durchlaufen. Jeder Iterator zeigt auf einen std::pair<const T,S>, wobei T und S die gleichen Typen sind, die Sie in Ihrer map angegeben haben.

Hier wäre das:

for (std::map<int, MyClass>::iterator it = Map.begin(); it != Map.end(); ++it)
{
  it->second.Method();
}

Wenn Sie weiterhin std::for_each verwenden möchten, übergeben Sie eine Funktion, die stattdessen einen std::pair<const int, MyClass>& als Argument verwendet.

Beispiel:

void CallMyMethod(std::pair<const int, MyClass>& pair) // could be a class static method as well
{
  pair.second.Method();
}

Und übergeben Sie es an std::for_each:

std::for_each(Map.begin(), Map.end(), CallMyMethod);
49
ereOn

Mit C++ 11 können Sie Folgendes tun:

for (const auto& kv : myMap) {
    std::cout << kv.first << " has value " << kv.second << std::endl;
}

AKTUALISIEREN:

const auto ist sicherer, wenn Sie die Karte nicht ändern möchten.

74
Sebastian

Wie wäre es mit einem einfachen C++? (Beispiel entsprechend der Anmerkung von @Noah Roberts behoben)

for(std::map<int, MyClass>::iterator itr = Map.begin(), itr_end = Map.end(); itr != itr_end; ++itr) {
  itr->second.Method();
}
8
bobah

C++ 14 bringt generische Lambdas ..__, dh wir können std :: for_each sehr leicht verwenden:

std::map<int, int> myMap{{1, 2}, {3, 4}, {5, 6}, {7, 8}};

std::for_each(myMap.begin(), myMap.end(), [](const auto &myMapPair) {
    std::cout << "first " << myMapPair.first << " second "
              << myMapPair.second << std::endl;
});

Ich denke, dass std :: for_each manchmal besser geeignet ist als ein einfacher Bereich für eine Schleife. Zum Beispiel, wenn Sie nur eine Teilmenge einer Karte durchlaufen möchten.

6
Christian Rapp

Es ist bedauerlich, dass Sie Boost nicht haben. Wenn Ihre STL-Implementierung jedoch die Erweiterungen enthält, können Sie mem_fun_ref und select2nd erstellen, um einen einzelnen, für for_each geeigneten Funktionsbereich zu erstellen. Der Code würde ungefähr so ​​aussehen:

#include <algorithm>
#include <map>
#include <ext/functional>   // GNU-specific extension for functor classes missing from standard STL

using namespace __gnu_cxx;  // for compose1 and select2nd

class MyClass
{
public:
    void Method() const;
};

std::map<int, MyClass> Map;

int main(void)
{
    std::for_each(Map.begin(), Map.end(), compose1(std::mem_fun_ref(&MyClass::Method), select2nd<std::map<int, MyClass>::value_type>()));
}

Wenn Sie keinen Zugriff auf compose1 (oder die Vorlage unary_compose) und select2nd haben, können Sie relativ einfach schreiben.

3
David Joyner

Für Programmierer, die auf diese Frage von Google gestoßen sind, gibt es einen guten Weg, Boost zu verwenden.

Erklärt hier: Kann boost :: foreach mit std :: map verwendet werden?

Echtes Beispiel für Ihre Bequemlichkeit:

// typedef in include, given here for info : 
typedef std::map<std::string, std::string> Wt::WEnvironment::CookieMap

Wt::WEnvironment::CookieMap cookie_map = environment.cookies();

BOOST_FOREACH( const Wt::WEnvironment::CookieMap::value_type &cookie, cookie_map )
{
    std::cout << "cookie : " << cookie.first << " = " << cookie.second << endl;
}

genießen.

2
Offirmo

Hier ein Beispiel, wie Sie for_each für eine Karte verwenden können. 

std::map<int, int> map;

map.insert(std::pair<int, int>(1, 2));
map.insert(std::pair<int, int>(2, 4));
map.insert(std::pair<int, int>(3, 6));

auto f = [](std::pair<int,int> it) {std::cout << it.first + it.second << std::endl; };
std::for_each(map.begin(), map.end(), f);
0
HmdRmz

Soweit ich mich erinnere, kann die C++ - Map mithilfe von map.begin () einen Iterator von Schlüsseln zurückgeben. Mit diesem Iterator können Sie alle Tasten durchlaufen, bis sie map.end () erreichen, und den entsprechenden Wert erhalten: C++ - Karte

0
vodkhang

Ich habe dies vor einiger Zeit geschrieben, um genau das zu tun, wonach Sie suchen.

namespace STLHelpers
{
    //
    // iterator helper type for iterating through the *values* of key/value collections
    //

    /////////////////////////////////////////////
    template<typename _traits>
    struct _value_iterator
    {
        explicit _value_iterator(typename _traits::iterator_type _it)
            : it(_it)
        {
        }

        _value_iterator(const _value_iterator &_other)
            : it(_other.it)
        {
        }

        friend bool operator==(const _value_iterator &lhs, const _value_iterator &rhs)
        {
            return lhs.it == rhs.it;
        }

        friend bool operator!=(const _value_iterator &lhs, const _value_iterator &rhs)
        {
            return !(lhs == rhs);
        }

        _value_iterator &operator++()
        {
            ++it;
            return *this;
        }

        _value_iterator operator++(int)
        {
            _value_iterator t(*this);
            ++*this;
            return t;
        }

        typename _traits::value_type &operator->()
        {
            return **this;
        }

        typename _traits::value_type &operator*()
        {
            return it->second;
        }

        typename _traits::iterator_type it;
    };

    template<typename _tyMap>
    struct _map_iterator_traits
    {
        typedef typename _tyMap::iterator iterator_type;
        typedef typename _tyMap::mapped_type value_type;
    };

    template<typename _tyMap>
    struct _const_map_iterator_traits
    {
        typedef typename _tyMap::const_iterator iterator_type;
        typedef const typename _tyMap::mapped_type value_type;
    };
}
0
moswald

Wird es für dich funktionieren? 

class MyClass;
typedef std::pair<int,MyClass> MyPair;
class MyClass
{
  private:
  void foo() const{};
public:
static void Method(MyPair const& p) 
{
    //......
        p.second.foo();
};
}; 
// ...
std::map<int, MyClass> Map;
//.....
std::for_each(Map.begin(), Map.end(), (&MyClass::Method));
0
a1ex07

Nur ein Beispiel:

template <class key, class value>
class insertIntoVec
{
public:
    insertIntoVec(std::vector<value>& vec_in):m_vec(vec_in)
    {}

    void operator () (const std::pair<key, value>& rhs)  
    {   
        m_vec.Push_back(rhs.second);
    }

private:
    std::vector<value>& m_vec;
};

int main()
{
std::map<int, std::string> aMap;
aMap[1] = "test1";
aMap[2] = "test2";
aMap[3] = "test3";
aMap[4] = "test4";

std::vector<std::string> aVec;

aVec.reserve(aMap.size());
std::for_each(aMap.begin(), aMap.end(),
          insertIntoVec<int, std::string>(aVec) 
    );

}

0
aJ.