c++ - ostream_iterator for vector<vector<double>>

标签 c++ c++11

<分区>

我想弄明白为什么下面的代码不能编译

#include <vector>
#include <ostream>
#include <iterator>
#include <iostream>

template <class ostream>
ostream& operator<<(ostream& o, const std::vector<double>& data)
{
    std::copy(data.begin(), data.end(), std::ostream_iterator<double>(o, " "));
    return o;
}

template<class ostream>
ostream& operator<<(ostream& o, const std::vector<std::vector<double>>& data)
{
    std::copy(data.begin(), data.end(), std::ostream_iterator<std::vector<double>>(o, "\n"));
    return o;
}

int main(int argc, char **argv)
{
    std::vector<std::vector<double>> vecvec = {{1,2,3}, 
                                               {4,5,6}};
    std::cout << vecvec << std::endl;
}

我认为既然我已经定义了一个 operator<<对于 vector<double>我应该可以利用 ostream_iterator

相反,我得到了一个编译错误,如果我将代码更改为以下内容,那么一切都可以正常编译。

#include <vector>
#include <ostream>
#include <iterator>
#include <iostream>

template <class ostream>
ostream& operator<<(ostream& o, const std::vector<double>& data)
{
    std::copy(data.begin(), data.end(), std::ostream_iterator<double>(o, " "));
    return o;
}

template<class ostream>
ostream& operator<<(ostream& o, const std::vector<std::vector<double>>& data)
{
    /** changed to manually looping **/
    for (const auto& line : data)
    {
        o << line << "\n";
    }
    return o;
}

int main(int argc, char **argv)
{
    std::vector<std::vector<double>> vecvec = {{1,2,3}, 
                                               {4,5,6}};
    std::cout << vecvec << std::endl;
}

我做错了什么?

最重要的是...谁能向我解释为什么 ostream_iterator这里编译失败?

我可以找到解决方法并解决我的问题,但似乎我还没有完全理解 ostream_iterator 是如何产生的作品

这是编译器(gcc 4.8.5)的输出

In file included from /opt/compiler-explorer/gcc-4.8.5/include/c++/4.8.5/iterator:66:0,from <source>:3:

/opt/compiler-explorer/gcc-4.8.5/include/c++/4.8.5/bits/stream_iterator.h: In instantiation of 'std::ostream_iterator<_Tp, _CharT, _Traits>& std::ostream_iterator<_Tp, _CharT, _Traits>::operator=(const _Tp&) [with _Tp = std::vector<double>; _CharT = char; _Traits = std::char_traits<char>]':

/opt/compiler-explorer/gcc-4.8.5/include/c++/4.8.5/bits/stl_algobase.h:335:18:   required from 'static _OI std::__copy_move<false, false, std::random_access_iterator_tag>::__copy_m(_II, _II, _OI) [with _II = std::vector<double>*; _OI = std::ostream_iterator<std::vector<double> >]'

/opt/compiler-explorer/gcc-4.8.5/include/c++/4.8.5/bits/stl_algobase.h:390:70:   required from '_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false; _II = std::vector<double>*; _OI = std::ostream_iterator<std::vector<double> >]'

/opt/compiler-explorer/gcc-4.8.5/include/c++/4.8.5/bits/stl_algobase.h:428:38:   required from '_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false; _II = __gnu_cxx::__normal_iterator<std::vector<double>*, std::vector<std::vector<double> > >; _OI = std::ostream_iterator<std::vector<double> >]'

/opt/compiler-explorer/gcc-4.8.5/include/c++/4.8.5/bits/stl_algobase.h:460:17:   required from '_OI std::copy(_II, _II, _OI) [with _II = __gnu_cxx::__normal_iterator<std::vector<double>*, std::vector<std::vector<double> > >; _OI = std::ostream_iterator<std::vector<double> >]'

<source>:17:96:   required from 'ostream& operator<<(ostream&, std::vector<std::vector<double> >&) [with ostream = std::basic_ostream<char>]'

<source>:26:18:   required from here

/opt/compiler-explorer/gcc-4.8.5/include/c++/4.8.5/bits/stream_iterator.h:198:13: error: cannot bind 'std::ostream_iterator<std::vector<double> >::ostream_type {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'

  *_M_stream << __value;

             ^

In file included from <source>:2:0:

/opt/compiler-explorer/gcc-4.8.5/include/c++/4.8.5/ostream:602:5: error:   initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = std::vector<double>]'

     operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)

     ^

Compiler returned: 1

最佳答案

为什么std::ostream_iterator的原因不适用于您的代码是因为 operator<<您定义的是在全局命名空间中,而不是在命名空间中 std .

std::ostream_iterator is defined调用operator<<喜欢ostr << value , 它执行 argument-dependent lookup (日常事件能力)。 ADL 未找到任何 operator<<在这种情况下,因为没有 operator<<std::ostream& 之间和 std::vector<double>在命名空间 `std.

中定义

ADL 找到关联的命名空间和类后,重载集将与 unqualified name lookup 找到的重载集合并.在不合格的名称查找中引用 cppreference:

[N]ame lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.

已添加重点

std::ostream_iteratorstd 里面命名空间,它调用 ostr << valuestd 里面命名空间。还有其他operator<<std 中定义命名空间,因此不合格的名称查找会找到一个 operator<<并停止。这发生在发现的函数被认为是否兼容之前。


不要向不属于您的类型添加运算符,除非您拥有其他类型。为了正确使用该语言,运算符必须在与类型相同的 namespace 中定义(以便可以通过 ADL 找到它)。但是,将函数添加到不属于您的 namespace 不是好的做法,并且会导致问题。对于 std 的情况, 它实际上是 undefined behavior .

关于c++ - ostream_iterator for vector<vector<double>>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51068753/

相关文章:

c++ - OpenGL深度测试在某些计算机上不起作用

c++ - 遍历 2.5D 网格

c++ - 创建与 C++11 随机 header 兼容的自定义分发

c++ - "integral"类型的函数重载

c++ - 如何区分ascii值和数字?

C++——OpenProcess 返回错误代码 87

c++ - 在 WinAPI、POSIX 或 API-OS 的其他扩展中是否存在 C++11 的所有级别的内存屏障?

c++ - Qt - 在 Windows 上按下 Alt 后防止菜单栏获取焦点

c++ - 函数内定义的空指针

c++ - std::threads 是在用户空间还是内核空间中管理的?