Domanda

Ho il prossimo codice:

#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 questo codice voglio solo copiare la mappa nel flusso di output. Per fare questo ho bisogno di definire l'operatore & Lt; & Lt; (..) - OK. Ma secondo i nomi che trovano le regole il compilatore non riesce a trovare il mio operatore & Lt; & Lt; ().
Perché std :: cout, std :: pair e std :: copy che ha chiamato il mio operatore & Lt; & Lt; - tutto dallo spazio dei nomi std.

Soluzione rapida: aggiungi il mio oerator < < allo std namespace - ma è brutto, imho.

Quali soluzioni o soluzioni alternative per questo problema conosci?

È stato utile?

Soluzione 2

Ho fondato un nuovo modo elegante per risolvere questo problema.
Ho molte idee di interesse quando leggi le risposte:

  • avvolgi iteratore, per trasformare std :: pair in std :: string;
  • wrap std :: pair, per avere la possibilità di sovraccaricare l'operatore < < (...);
  • usa il solito std :: for_each con funzione di stampa;
  • usa std :: for_each con boost :: labda - sembra carino, tranne l'accesso a std :: pair < > :: first e std :: pair < > :: secondi membri;

Penso che userò tutte queste idee in futuro per risolvere diversi altri problemi.
Ma per questo caso ho sottolineato che posso formulare il mio bproblema come & Quot; trasformare i dati della mappa in stringhe e scriverli nel flusso di output & Quot; invece " copia i dati della mappa nel flusso di uscita " ;. La mia soluzione è simile a:

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 );

Penso che questo metodo sia il più breve ed espressivo di altri.

Altri suggerimenti

Non esiste un modo standard per calcolare un std::pair perché, beh, il modo in cui lo vuoi stampare è probabilmente diverso dal modo in cui lo vuole il prossimo. Questo è un buon caso d'uso per un funzione personalizzata o una funzione lambda. Puoi quindi passarlo come argomento a std::for_each per fare il lavoro.

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";
    }
}

Per chiamare questa funzione dal tuo codice:

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

Vorrei solo sottolineare che l'aggiunta di cose allo spazio std :: namespace è illegale secondo lo standard C ++ (vedere la sezione 17.4.3.1).

Quello che vuoi è un iteratore in trasformazione. Questo tipo di iteratore avvolge un altro iteratore, inoltra tutti i metodi di posizionamento come operatore ++ e operatore ==, ma ridefinisce operatore * e operatore - & Gt ;.

Schizzo rapido:

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 + "]";
    }
...

Sto solo passando, ma questo ha fatto il lavoro per me, quindi può farlo per qualcun altro (versione ridotta):

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

Caso d'uso indicato:

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

Usando Boost Lambda, potresti provare qualcosa del genere. La versione che ho di Boost Lambda, in realtà non funziona, testerò e risolverò più tardi.

#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 ) );

[Preferirei eliminare questa risposta, ma la lascerò per ora, nel caso qualcuno ritenga interessante la discussione.]

Dato che è un'estensione ragionevole della libreria std, la metterei semplicemente nello spazio dei nomi std, specialmente se questa è una cosa sola. Puoi semplicemente dichiararlo statico per evitare che causi errori del linker, se qualcun altro fa la stessa cosa da qualche altra parte.

Un'altra soluzione che viene in mente è quella di creare un wrapper per std :: pair:

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;

più semplice e universale!

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

}); 

--- Va bene con C ++ 11

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top