Re: cannot write std::map via ostream_iterator? Organization: ...
James K. Lowden wrote:
Can you tell me why the program below does not compile?
std::ostream_iterator won't find the operator<< you want to use in the
global namespace.
I understand that ostream_iterator::operator=(rhs) calls
operator<<(ostream&, rhs) and as far as I'm concerned that operator is
declared, right after the typedef. But when two compilers disagree with
me, I usually like to admit I'm wrong.
It smells like a const problem, but it must be possible to write
std::pair<const string, string> to an ostream via an iterator. (Or
perhaps it has to do with the context of the template instantiation?)
Yes.
Here's the workaround I came up with.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <map>
#include <string>
#include <utility>
typedef std::map<std::string,std::string> map_ss;
// ostream_iterator won't find this
// in the global namespace
std::ostream &operator<<(
std::ostream& os,
const map_ss::value_type& elem
) {
// or however it should be formatted.
os << "(" << elem.first << "," << elem.second << ")";
return os;
}
// so we fake it by adding some namespace indirection.
namespace fake_pair {
struct pair {
typedef ::map_ss::value_type pair_ss;
const pair_ss &p_;
pair(const pair_ss &p) : p_(p) {}
};
std::ostream &operator<<(std::ostream &o, const pair &p) {
return ::operator<<(o,p.p_);
}
}
int main()
{
map_ss ml;
ml["hello"] = "world"; // see if something prints.
std::copy(
ml.begin(),
ml.end(),
std::ostream_iterator<fake_pair::pair>(std::cout)
);
}
FWIW the above compiles and runs with VS8 and compiles with
http://www.comeaucomputing.com/tryitout/
If need be, fake_name::pair, fake_name::operator<< and ::operator<<
above, can be made into templates.
I had to search a bit to find the problem. I googled(tm) for
ostream_iterator namespace, and I found some similar problems I'm sure
there's a better one than mine out there.
http://accu.org/index.php/journals/242 which has a nice link to
http://www.boostpro.com/writing/n1691.html
http://discuss.joelonsoftware.com/default.asp?joel.3.191244.5
It wasn't hard to convince myself that the problem is with namespaces
and lookup, I tried (code below typed from memory):
std::ostream &operator<<(std::ostream &o, const std::pair<int,int> &p) {
o << p.first << "," << p.second;
return o;
}
int main() {
std::ostream_iterator<std::pair<int,int> > os(std::cout);
os = std::pair<int,int>(1,2);
}
and also tried this example with operator<< in the xyx namespace and
then in the global namespace,
namespace xyz {
class U {};
std::ostream &operator<<(std::ostream &o, const U &) {
o << "(xyz::U)";
return o;
}
}
int main() {
std::ostream_iterator<xyz::U> os(std::cout);
os = xyz::U();
std::cout << xyz::U() << std::endl;
}
HTH
LR
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]