[ACCEPTED]-std::copy to std::cout for std::pair-operator-overloading
There is no standard way to cout a std::pair
because, well, how 6 you want it printed is probably different 5 from the way the next guy wants it. This 4 is a good use case for a custom functor 3 or a lambda function. You can then pass 2 that as an argument to std::for_each
to do the work.
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";
}
}
To 1 call this functor from your code:
std::for_each(some_map.begin(),
some_map.end(),
PrintMyMap<MyMap::value_type>(std::cout));
I've founded one new elegant way to solve 10 this problem.
I've got many interest ideas 9 when read answers:
- wrap iterator, for transform std::pair to std::string;
- wrap std::pair, for have a chance to overload operator<<(...);
- use usual std::for_each with printing functor;
- use std::for_each with boost::labda - looks nice, except accessing to std::pair< >::first and std::pair< >::second members;
I think I will use all 8 of this ideas in future for solve different 7 other problems.
But for this case I've understaded 6 that I can formulate my bproblem as "transform 5 map's data to strings and write them to 4 output stream" instead "copy map's data 3 to ouput stream". My solution looks like:
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 );
I 2 think this method is most short and expressive 1 than others.
I'd just like to point out that adding things 2 to the std:: namespace is illegal according 1 to the C++ Standard (see section 17.4.3.1).
What you want is a transforming iterator. This 4 kind of iterator wraps another iterator, forwards 3 all positioning methods like operator++ and 2 operator==, but redefines operator* and 1 operator->.
Quick sketch :
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 + "]";
}
...
Just passing by, but this did the job for 2 me, so it can for somebody else (cut version):
template<typename First, typename Second>
struct first_of {
First& operator()(std::pair<First, Second>& v) const {
return v.first;
}
};
Use 1 case given:
transform (v.begin (), v.end (),
ostream_iterator<int>(cout, "\n"), first_of<int, string> ());
[I'd rather delete this answer, but I'll 4 leave it for now, in case someone finds 3 the discussion interesting.]
Since it's a reasonable extension to the std library, I'd just put it in std namespace, especially if this is a one time thing. You can just declare it static to prevent it from causing linker errors, should someone else do the same thing someplace else.
Another solution 2 that comes to mind is to create a wrapper 1 for 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) { ... }
Using Boost Lambda, you could try something 3 like this. The version I have of Boost Lambda, this 2 doesn't actually work, I'll test and fix 1 later.
#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 ) );
for (const auto& your_pair : your_container)
your_stream << "[" << your_pair.first << "," << your_pair.second << "]" << endl;
more simple and universal !
0
Here is an adaptor to use with std::copy
and std::ostream_iterator
for 4 the std::pair
type. You end up holding one extra 3 reference, but the compiler optimization 2 may take care of it. BTW, the first type 1 in std::pair
of the std::map::value_type
will be a const
.
template <typename pair_type>
class pair_adaptor
{
public:
const pair_type &m;
pair_adaptor(const pair_type &a) : m(a) {}
friend std::ostream &operator << (std::ostream &out,
const pair_adaptor <pair_type> &d)
{
const pair_type &m = d.m;
return out << m.first << " => " << m.second;
}
};
typedef std::map<size_t, size_t>::value_type value_type;
std::copy (mymap.begin(), mymap.end(),
std::ostream_iterator <
pair_adaptor <value_type> > (std::cout, "\n"));
std::copy (mymap.begin(), mymap.end(),
std::ostream_iterator <
pair_adaptor <
std::pair<const size_t, size_t>>> (std::cout, "\n"));
for_each(some_map.begin(), some_map.end(), [](const std::map < size_t, size_t >::value_type &ite){
cout<<ite.first<<" "<<ite.second<<endl;
});
--- It is fine with C++11
0
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.