[英]std::copy to std::cout for std::pair
我有下一个代码:
#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;
}
在这段代码中,我只想将 map 复制到 output stream。 为此,我需要定义运算符 <<(..) - 好的。 但是根据名称查找规则编译器找不到我的操作符<<()。
因为 std::cout、std::pair 和 std::copy 调用了我的 operator<< - 都来自命名空间 std。
快速解决方案 - 将我的 oerator<< 添加到 std 命名空间 - 但它很难看,恕我直言。
您知道此问题的哪些解决方案或解决方法?
没有标准的方法来计算std::pair
因为,你想要它的打印方式可能与下一个人想要的方式不同。 这是自定义仿函数或 lambda function 的一个很好的用例。 然后,您可以将其作为参数传递给std::for_each
来完成这项工作。
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";
}
}
要从您的代码中调用此函子:
std::for_each(some_map.begin(),
some_map.end(),
PrintMyMap<MyMap::value_type>(std::cout));
我已经建立了一种新的优雅方法来解决这个问题。
阅读答案时,我有很多有趣的想法:
我想我将来会使用所有这些想法来解决其他不同的问题。
但是对于这种情况,我理解我可以将我的问题表述为“将地图的数据转换为字符串并将它们写入 output 流”而不是“将地图的数据复制到输出流”。 我的解决方案如下所示:
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 );
我认为这种方法比其他方法最简短、最具表现力。
我只想指出,根据 C++ 标准(参见第 17.4.3.1 节),向 std:: 命名空间添加内容是非法的。
你想要的是一个转换迭代器。 这种迭代器包装了另一个迭代器,转发所有定位方法如operator++和operator==,但重新定义了operator*和operator->。
速写:
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 + "]";
}
...
只是路过,但这为我做了工作,所以它可以为其他人(剪辑版):
template<typename First, typename Second>
struct first_of {
First& operator()(std::pair<First, Second>& v) const {
return v.first;
}
};
给出的用例:
transform (v.begin (), v.end (),
ostream_iterator<int>(cout, "\n"), first_of<int, string> ());
[我宁愿删除这个答案,但我会暂时保留它,以防有人觉得讨论有趣。]
因为它是对 std 库的合理扩展,所以我只是将它放在 std 命名空间中,特别是如果这是一次性的事情。
你可以声明它 static 以防止它导致 linker 错误,如果其他人在其他地方做同样的事情。
想到的另一个解决方案是为 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) { ... }
使用 Boost Lambda,你可以尝试这样的事情。 我的Boost Lambda的版本,这个确实不行,我稍后测试和修复。
#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;
更简单通用!
这是用于std::pair
类型的std::copy
和std::ostream_iterator
的适配器。 您最终会持有一个额外的引用,但编译器优化可能会处理它。 顺便说一句, std::pair
的std::map::value_type
的第一个类型将是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;
});
--- C++11 没问题
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.