Pergunta

Eu tenho seguinte código:

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

Neste código Eu só quero mapa cópia ao fluxo de saída. Para fazer isso eu preciso definir operador << (..) - OK. Mas os nomes de acordo encontrando regras compilador não pode encontrar meu operador << ().
Porque std :: cout, std :: pair e std :: exemplar, que chamou o meu operador << -. Tudo a partir de std namespace

solução rápida - adicionar o meu oerator << para namespace std -. Mas é feio, imho

Que soluções ou solução para este problema é que você sabe?

Foi útil?

Solução 2

Eu fundou uma nova maneira elegante para resolver este problema.
Eu tenho muitas idéias de juros quando ler as respostas:

  • embrulhar iterador, para transformar std :: pair para std :: string;
  • envoltório std :: pair, para ter uma chance de operador sobrecarga << (...);
  • usar o habitual std :: for_each com a impressão functor;
  • uso std :: for_each com boost :: labda - parece bom, exceto o acesso para std :: pair <> :: primeiro e std :: pair <> :: segundo membros;

Eu acho que vou usar tudo isso idéias no futuro para resolver diferentes outros problemas.
Mas para este caso eu understaded que eu posso formular o meu bproblem como "transformar os dados do mapa para cordas e gravá-los em fluxo de saída" em vez "copiar dados do mapa para ouput stream". Minha solução parece com:

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

Eu acho que este método é mais curto e expressivo do que outros.

Outras dicas

Não há nenhuma maneira padrão para cout um std::pair porque, bem, como você deseja que ele impresso é provavelmente diferente da forma como o próximo cara quer. Este é um caso bom uso para um functor personalizada ou uma função lambda. Você pode então passar isso como um argumento para std::for_each para fazer o trabalho.

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

Para chamar esta functor do seu código:

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

Eu apenas gostaria de salientar que a adição de coisas para o std :: namespace está de acordo ilegal para o padrão C ++ (consulte a seção 17.4.3.1).

O que você quer é um iterador transformadora. Este tipo de iterador envolve outro iterador, encaminha todos os métodos de posicionamento como operador ++ e operador ==, mas operador redefine * e operador ->.

O esboço rápido:

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

Apenas passando, mas isso fez o trabalho para mim, para que ele possa por outra pessoa (versão cut):

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

Use caso dado:

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

Usando o impulso Lambda, você poderia tentar algo como isto. A versão que eu tenho de impulso Lambda, isso na verdade não trabalho, eu vou testar e corrigir mais tarde.

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

[Eu prefiro apagar esta resposta, mas vou deixar isso por agora, no caso de alguém acha a discussão interessante.]

Uma vez que é uma extensão razoável para a biblioteca std, eu tinha acabado de colocá-lo no namespace std, especialmente se esta é uma coisa de uma vez. Você pode apenas declarar estático para impedir que cause erros vinculador, deve alguém fazer a mesma coisa em outro lugar.

Outra solução que vem à mente é a de criar um wrapper para 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;

mais simples e universal!

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

}); 

--- É bem com C ++ 11

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top