std::copy 到 std::cout 以获得 std::pair

发布于 2024-07-15 01:39:46 字数 1084 浏览 8 评论 0原文

我有下一个代码:

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

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

快速解决方案 - 添加我的操作器<< 到 std 命名空间 - 但它很丑陋,恕我直言。

您知道该问题有哪些解决方案或解决方法?

I have next code:

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

In this code I just want copy map to output stream. For do this I need define operator <<(..) - OK.
But according names finding rules compiler can't find my operator<<().
Because std::cout, std::pair and std::copy which called my operator<< - all from namespace std.

Quick solution - add my oerator<< to std namespace - but it is ugly, imho.

What solutions or workaround for this problem do you know?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

如梦亦如幻 2024-07-22 01:39:46

没有标准的方法来计算 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));

There is no standard way to cout a std::pair because, well, how you want it printed is probably different from the way the next guy wants it. This is a good use case for a custom functor or a lambda function. You can then pass 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 call this functor from your code:

std::for_each(some_map.begin(),
              some_map.end(),
              PrintMyMap<MyMap::value_type>(std::cout));
森末i 2024-07-22 01:39:46

我发明了一种新的优雅方法来解决这个问题。
在阅读答案时,我有很多有趣的想法:

  • 包装迭代器,用于将 std::pair 转换为 std::string;
  • 包装 std::pair,用于有机会重载运算符<<(。 ..);
  • 使用通常的 std::for_each 与打印函子;
  • 使用 std::for_each 与 boost::labda - 看起来不错,除了访问 std::pair
    >::first 和 std::pair< >::第二位成员;

我想我将来会使用所有这些想法来解决其他不同的问题。
但对于这种情况,我知道我可以将我的问题表述为“将映射的数据转换为字符串并将它们写入输出流”而不是“将映射的数据复制到输出流”。 我的解决方案如下:

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've founded one new elegant way to solve this problem.
I've got many interest ideas 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 of this ideas in future for solve different other problems.
But for this case I've understaded that I can formulate my bproblem as "transform map's data to strings and write them to output stream" instead "copy map's data 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 think this method is most short and expressive than others.

审判长 2024-07-22 01:39:46

我只想指出,根据 C++ 标准,向 std:: 命名空间添加内容是非法的(请参阅第 17.4.3.1 节)。

I'd just like to point out that adding things to the std:: namespace is illegal according to the C++ Standard (see section 17.4.3.1).

薄情伤 2024-07-22 01:39:46

你想要的是一个转换迭代器。 这种迭代器包装了另一个迭代器,转发了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 + "]";
    }
...

What you want is a transforming iterator. This kind of iterator wraps another iterator, forwards all positioning methods like operator++ and operator==, but redefines operator* and 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 + "]";
    }
...
韵柒 2024-07-22 01:39:46

只是路过,但这对我来说完成了工作,所以对其他人也可以(剪切版本):

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

Just passing by, but this did the job for 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 case given:

transform (v.begin (), v.end (), 
           ostream_iterator<int>(cout, "\n"), first_of<int, string> ());
暖阳 2024-07-22 01:39:46

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

Using Boost Lambda, you could try something like this. The version I have of Boost Lambda, this doesn't actually work, I'll test and fix 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 ) );
柒夜笙歌凉 2024-07-22 01:39:46

[我宁愿删除这个答案,但我会暂时保留它,以防有人觉得讨论有趣。]

由于它是 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) { ... }

[I'd rather delete this answer, but I'll leave it for now, in case someone finds 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 that comes to mind is to create a wrapper 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) { ... }
万劫不复 2024-07-22 01:39:46
    for (const auto& your_pair : your_container)
        your_stream << "[" << your_pair.first << "," << your_pair.second << "]" << endl;

更加简单通用!

    for (const auto& your_pair : your_container)
        your_stream << "[" << your_pair.first << "," << your_pair.second << "]" << endl;

more simple and universal !

厌味 2024-07-22 01:39:46

这是一个与 std::copystd::ostream_iterator 一起使用的 std::pair 类型的适配器。 您最终会保留一个额外的引用,但编译器优化可能会处理它。 顺便说一句,std::map::value_typestd::pair 中的第一个类型将是 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"));

Here is an adaptor to use with std::copy and std::ostream_iterator for the std::pair type. You end up holding one extra reference, but the compiler optimization may take care of it. BTW, the first type 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"));
晨敛清荷 2024-07-22 01:39:46
 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就可以了

 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文