Frage

Ich habe nächsten Code:

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

//namespace std
//{

std::ostream& operator << ( std::ostream& out, 
                const std::pair< size_t, size_t >& rhs )
{
    out << rhs.first << ", " << rhs.second;
    return out;
}
//}

int main() 
{

    std::map < size_t, size_t > some_map;

    // fill  some_map with random values
    for ( size_t i = 0; i < 10; ++i )
    {
        some_map[ rand() % 10 ] = rand() % 100;
    }

    // now I want to output this map
    std::copy( 
        some_map.begin(), 
        some_map.end(), 
        std::ostream_iterator< 
              std::pair< size_t, size_t > >( std::cout, "\n" ) );

    return 0;
}

In diesem Code Ich möchte nur Karte Ausgabestrom kopieren. Dazu muss ich definieren operator << (..) - OK. Aber nach Namen Regeln Compiler kann die Suche nach meinem Bediener nicht gefunden << ().
Weil std :: cout, std :: pair und std :: Kopie, die meinen Operator genannt << - alles aus Namensraum std

.

Schnelle Lösung - nehmen Sie mich oerator << zum std-Namespace - aber es ist hässlich, imho

.

Welche Lösungen oder Abhilfe für dieses Problem kennen Sie?

War es hilfreich?

Lösung 2

Ich habe eine neue elegante Art und Weise begründet, dieses Problem zu lösen.
Ich habe viele Ideen Interesse bekam, wenn Antworten lesen:

  • Wrap Iterator für Transformation std :: pair std :: string;
  • Wrap std :: pair, für eine Chance haben, Betreiber zu überlasten << (...);
  • verwenden übliche std :: for_each mit Druck Funktors;
  • Verwendung std :: for_each mit boost :: labda - sieht nett aus, außer dem Zugriff auf std :: pair <> :: ersten und std :: pair <> :: zweites Element;

Ich denke, ich werde alle diese Ideen in Zukunft nutzen, um verschiedene andere Probleme zu lösen.
Aber für diesen Fall habe ich understaded, dass ich meine bproblem formulieren kann als „Kartendaten in Strings umwandeln und schreiben sie auf Ausgabestrom“ statt „Kopie Karte des Datenstroms an ouput“. Meine Lösung sieht so aus:

namespace
{
std::string toString( const std::pair< size_t, size_t >& data)
{
    std::ostringstream str;
    str << data.first << ", " << data.second;
    return str.str();
}
} // namespace anonymous

std::transform( 
    some_map.begin(), 
    some_map.end(), 
    std::ostream_iterator< std::string >( std::cout, "\n" ),
    toString );

Ich denke, diese Methode ist sehr kurz und ausdrucksvoller als andere.

Andere Tipps

Es gibt keine Standardmethode eine std::pair cout weil, na ja, wie Sie es gedruckt werden sollen wahrscheinlich anders als die Art und Weise ist der nächste Kerl es will. Dies ist ein guter Anwendungsfall für eine benutzerdefinierte Funktors oder eine Lambda-Funktion. Anschließend können Sie das als Argument übergeben std::for_each der Arbeit zu tun.

typedef std::map<size_t, size_t> MyMap;

template <class T>
struct PrintMyMap : public std::unary_function<T, void>
{
    std::ostream& os;
    PrintMyMap(std::ostream& strm) : os(strm) {}

    void operator()(const T& elem) const
    {
        os << elem.first << ", " << elem.second << "\n";
    }
}

Um diese Funktor aus dem Code aufrufen:

std::for_each(some_map.begin(),
              some_map.end(),
              PrintMyMap<MyMap::value_type>(std::cout));

Ich mag nur darauf hinweisen, dass die Dinge auf das std :: Namespace hinzugefügt nach dem C ++ Standard illegal ist (siehe Abschnitt 17.4.3.1).

Was Sie wollen, ist eine transformierende Iterator. Diese Art von Iterator wickelt einen anderen Iterator, leitet alle Positionierungsmethoden wie Operator ++ und Operator ==, aber neu definiert Operator * und Operator. ->

Schnelle Skizze:

template <typename ITER> 
struct transformingIterator : private ITER {
    transformingIterator(ITER const& base) : ITER(base) {}
    transformingIterator& operator++() { ITER::operator++(); return *this; }
    std::string operator*() const
    {
        ITER::value_type const& v = ITER::operator*();
        return "[" + v->first +", " + v->second + "]";
    }
...

gerade vorbei, aber dies hat den Job für mich, so kann es für jemand anderen (gekürzte Fassung):

template<typename First, typename Second>
struct first_of {
    First& operator()(std::pair<First, Second>& v) const {
        return v.first;
    }
};

Anwendungsfall gegeben:

transform (v.begin (), v.end (), 
           ostream_iterator<int>(cout, "\n"), first_of<int, string> ());

Mit Boost-Lambda, könnten Sie so etwas wie dies versuchen. Die Version, die ich von Boost-Lambda haben, bedeutet dies nicht wirklich funktionieren, werde ich testen und später beheben.

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

using namespace boost::lambda;

std::for_each( some_map.begin(), some_map.end(), 
               std::cout << bind( &std::map<size_t,size_t>::value_type::first, _1 )
                         << ","
                         << bind( &std::map<size_t,size_t>::value_type::second, _1 ) );

[Ich würde eher diese Antwort löschen, aber ich werde es jetzt verlassen, falls jemand die Diskussion interessant findet.]

Da es sich um eine angemessene Verlängerung der std Bibliothek ist, würde ich in std-Namespace setzen es einfach, vor allem, wenn es sich um eine einmalige Sache. Sie können nur erklären, es statisch, es zu verhindern, dass Linkerfehler verursacht, sollte jemand anderes sonst die gleiche Sache irgendwo tun.

Eine andere Lösung, die den Sinn kommt, ist ein Wrapper für std :: pair zu erstellen:

template<class A, class B>
struct pairWrapper {
  const std::pair<A,B> & x;
  pairWrapper(const std::pair<A,B> & x) : x(x) {}
}

template<class A,class B>
std::ostream & operator<<(std::ostream & stream, const pairWrapper<A,B> & pw) { ... }
    for (const auto& your_pair : your_container)
        your_stream << "[" << your_pair.first << "," << your_pair.second << "]" << endl;

einfacher und universell!

 for_each(some_map.begin(), some_map.end(), [](const std::map < size_t, size_t >::value_type &ite){
             cout<<ite.first<<" "<<ite.second<<endl;

}); 

--- Es ist schön, mit C ++ 11

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top