【问题标题】:Why does std::pair<char, std::string> have problems with std::copy to ostream为什么 std::pair<char, std::string> 与 std::copy 到 ostream 有问题
【发布时间】:2018-02-02 07:52:20
【问题描述】:

有人可以解释为什么如果我删除 cmets 下面的代码将无法编译吗?

    #include <iostream>
    #include <string>
    #include <utility>
    #include <vector>
    #include <iterator>
    #include <algorithm>

    std::pair<char, std::string> uncons(const std::string & s) {
        std::string::size_type len = s.length();

        if (len == 1) {
            return std::make_pair(s[0], "");
        } else if (len > 1) {
            return std::make_pair(s[0], s.substr(1));
        }

        throw "Ooops, empty string";
    }

    std::ostream& operator<<(std::ostream & out, const std::pair<char, std::string> & p) {
        if (p.second.length() > 0) {
            out << "(\'" << p.first << "\', \"" << p.second << "\")";
        }
        return out;
    }

    int main(int argc, char ** argv) {

        auto ans = uncons("G4143");

        std::vector<std::pair<char, std::string> >  vec{ans};

        //If I remove the comments below the code fails to compile (GNU's g++14))
        /*std::copy
                (
                vec.begin(),
                vec.end(),
                std::ostream_iterator<std::pair<char, std::string> >(std::cout, "\n")
                );*/

        return 0;
    }

    /*

    In file included from /usr/include/c++/5/iterator:66:0,
                     from main.cpp:6:
    /usr/include/c++/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::pair<char, std::__cxx11::basic_string<char> >; _CharT = char; _Traits = std::char_traits<char>]’:
    /usr/include/c++/5/bits/stl_algobase.h:340:18:   required from ‘static _OI std::__copy_move<false, false, std::random_access_iterator_tag>::__copy_m(_II, _II, _OI) [with _II = std::pair<char, std::__cxx11::basic_string<char> >*; _OI = std::ostream_iterator<std::pair<char, std::__cxx11::basic_string<char> > >]’
    /usr/include/c++/5/bits/stl_algobase.h:402:44:   required from ‘_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false; _II = std::pair<char, std::__cxx11::basic_string<char> >*; _OI = std::ostream_iterator<std::pair<char, std::__cxx11::basic_string<char> > >]’
    /usr/include/c++/5/bits/stl_algobase.h:438:45:   required from ‘_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false; _II = __gnu_cxx::__normal_iterator<std::pair<char, std::__cxx11::basic_string<char> >*, std::vector<std::pair<char, std::__cxx11::basic_string<char> > > >; _OI = std::ostream_iterator<std::pair<char, std::__cxx11::basic_string<char> > >]’
    /usr/include/c++/5/bits/stl_algobase.h:471:8:   required from ‘_OI s/stream_iterator.h:198:13: note:   ‘const std::pair<char, 

....
std::__cxx11::basic_string<char> >’ is not derived from ‘const std::piecewise_constant_distribution<_RealType>’
      *_M_stream << __value;
                 ^
    In file included from /usr/include/c++/5/random:51:0,
                     from /usr/include/c++/5/bits/stl_algo.h:66,
                     from /usr/include/c++/5/algorithm:62,
                     from main.cpp:7:
    /usr/include/c++/5/bits/random.tcc:3160:5: note: candidate: template<class _RealType, class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::piecewise_linear_distribution<_RealType>&)
         operator<<(std::basic_ostream<_CharT, _Traits>& __os,
         ^
    /usr/include/c++/5/bits/random.tcc:3160:5: note:   template argument deduction/substitution failed:
    In file included from /usr/include/c++/5/iterator:66:0,
                     from main.cpp:6:
    /usr/include/c++/5/bits/stream_iterator.h:198:13: note:   ‘const std::pair<char, std::__cxx11::basic_string<char> >’ is not derived from ‘const std::piecewise_linear_distribution<_RealType>’
      *_M_stream << __value; 
    */

现在,如果我将 std::pair 的 std::string 部分包装在一个简单的类 (MyString) 中,那么一切都会按预期工作。下面的代码编译没有问题并按预期工作。

#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include <iterator>
#include <algorithm>

class MyString {

public:

    MyString(const std::string & s):str(s) {}

    std::string str;

};

std::pair<char, MyString> uncons(const std::string & s) {
    std::string::size_type len = s.length();

    if (len == 1) {
        return std::make_pair(s[0], MyString(""));
    } else if (len > 1) {
        return std::make_pair(s[0], MyString(s.substr(1)));
    }

    throw "Ooops, empty string";
}

std::ostream& operator<<(std::ostream & out, const std::pair<char, MyString> & p) {
    if (p.second.str.length() > 0) {
        out << "(\'" << p.first << "\', \"" << p.second.str << "\")";
    }
    return out;
}

int main(int argc, char ** argv) {

    auto ans = uncons("G4143");

    std::vector<std::pair<char, MyString> >  vec{ans};


    std::copy
            (
            vec.begin(),
            vec.end(),
            std::ostream_iterator<std::pair<char, MyString> >(std::cout, "\n")
            );

    return 0;
}

谁能解释为什么会这样?我按照建议修改了我的帖子,并尝试完整地附上错误消息,但论坛不允许编译器吐出的整个消息。

【问题讨论】:

标签: c++


【解决方案1】:

一如既往,它是 ADL。

operator&lt;&lt; 是通过 ADL 找到的,所以在相关的命名空间中。由于std::string 的关联命名空间只是命名空间::std(声明它和特征模板参数类型参数),您必须在该命名空间中定义operator&lt;&lt; 重载。

事实上,如果你破解它并强制你的重载进入std 命名空间,它“工作”:http://coliru.stacked-crooked.com/a/7c2486ae963c2a64警告这样做是不合法的

包装自定义类型后,该类型的声明命名空间将参与 ADL 查找。

Extra 我通常为基元或非用户定义类型(可选地)提供自定义流式处理是创建一个操纵器来执行此操作,请参见例如Template specialization (boost::lexical_cast)

【讨论】:

    猜你喜欢
    • 2010-10-12
    • 1970-01-01
    • 2022-01-20
    • 2014-10-24
    • 1970-01-01
    • 2023-03-21
    • 2020-12-05
    • 2021-03-23
    相关资源
    最近更新 更多