std :: copy到std :: cout的std :: cout

时间:2009-03-11 11:06:15

标签: c++ stl namespaces operator-overloading

我有下一个代码:

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

在这段代码中,我只想要复制映射到输出流。为此,我需要定义运算符&lt;&lt;(...) - 好的。 但根据名称查找规则编译器无法找到我的运算符&lt;&lt;() 因为std :: cout,std :: pair和std :: copy调用了我的运算符&lt;&lt; - 全部来自命名空间标准。

快速解决方案 - 添加我的oerator&lt;&lt;到std命名空间 - 但它很难看,imho。

您知道这个问题的解决方案或解决方法吗?

10 个答案:

答案 0 :(得分:16)

没有标准的方法来宣传std::pair,因为,你想要它的打印方式可能与下一个人想要它的方式不同。这是自定义函子或lambda函数的一个很好的用例。然后,您可以将其作为参数传递给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));

答案 1 :(得分:14)

我已经找到了一种解决这个问题的新方法 在阅读答案时,我有很多有趣的想法:

  • 包装迭代器,用于将std :: pair转换为std :: string;
  • wrap std :: pair,有机会重载运算符&lt;&lt;(...);
  • 使用通常的std :: for_each和print functor;
  • 使用std :: for_each和boost :: labda - 看起来不错,除了访问std :: pair&lt; &gt; :: first和std :: pair&lt; &gt; ::第二名成员;

我想我将来会用这些想法来解决其他不同的问题 但是对于这种情况,我已经明白我可以将我的问题表述为“将地图的数据转换为字符串并将其写入输出流”而不是“将地图的数据复制到输出流”。我的解决方案如下:

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

我认为这种方法比其他方法更短,更具表现力。

答案 2 :(得分:10)

我只想指出,根据C ++标准,将内容添加到std :: namespace是非法的(参见第17.4.3.1节)。

答案 3 :(得分:5)

你想要的是一个转换迭代器。这种迭代器包装另一个迭代器,转发所有定位方法,如operator ++和operator ==,但重新定义operator *和operator-&gt;。

快速草图:

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

答案 4 :(得分:4)

刚刚路过,但这对我来说很合适,所以对其他人来说(剪切版):

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

答案 5 :(得分:2)

[我宁愿删除这个答案,但我现在暂时离开,以防有人发现讨论有趣。]

因为它是对std库的合理扩展,所以我只是把它放在std命名空间中,特别是如果这是一次性的话。您可以将其声明为静态以防止它导致链接器错误,如果其他人在其他地方执行相同的操作。

另一个想到的解决方案是为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) { ... }

答案 6 :(得分:2)

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

答案 7 :(得分:1)

    for (const auto& your_pair : your_container)
        your_stream << "[" << your_pair.first << "," << your_pair.second << "]" << endl;
更简单,更普遍!

答案 8 :(得分:0)

 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很好用

答案 9 :(得分:0)

这里是std::copy类型的std::ostream_iteratorstd::pair适配器。您最终拥有一个额外的参考,但是编译器优化可以解决这个问题。顺便说一句,std::pairstd::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"));