首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >std::experimental::ostream_joiner和std::配对

std::experimental::ostream_joiner和std::配对
EN

Stack Overflow用户
提问于 2017-09-27 18:17:55
回答 2查看 863关注 0票数 6

在c++17/g++7中,终于出现了长期错过的ostream_joiner。它允许将适当的输出输出到ostreams,用内固定分隔符分隔集合元素。

代码语言:javascript
复制
#include <algorithm>
#include <experimental/iterator>
#include <iostream>
#include <iterator>
#include <vector>
#include <string>

using string = std::string;
#if 1
struct pair {
    string first;
    string second;
};
#else
using pair = std::pair<string,string>;
#endif


std::ostream& operator<<(std::ostream& lhs, const pair &p) {
    return lhs << p.first << "=" << p.second;
}

int main()
{
    std::vector<pair> pairs = {{"foo", "bar"}, {"baz", "42"}};
    std::copy(std::begin(pairs),
          std::end(pairs),
          std::experimental::make_ostream_joiner(std::cout, ", "));
}

当代码片段成功地编译和输出时..。

代码语言:javascript
复制
foo=bar, baz=42

..。在代码段中将#if 1更改为#if 0会使编译器抱怨缺少正确的shift操作符:

代码语言:javascript
复制
main.cpp:29:70:   required from here
/usr/local/include/c++/7.2.0/experimental/iterator:88:10: error: no match for 
'operator<<' (operand types are 
'std::experimental::fundamentals_v2::ostream_joiner<const char*, char, 
std::char_traits<char> >::ostream_type {aka std::basic_ostream<char>}' and 
'const std::pair<std::__cxx11::basic_string<char>, 
std::__cxx11::basic_string<char> >')
  *_M_out << __value;

有人知道为什么吗?

更新

巴里对这个问题给出了正确答案。然而,它并没有解决这个问题,并且运行手动循环并不意味着重用现有的stl代码,因此这个问题被扩展到:

是否有可能使流操作符在不污染std名称空间的情况下工作?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-09-27 18:29:22

ostream_joiner实现的某个地方,可能会有这样的尝试:

代码语言:javascript
复制
os << value;

其中osstd::basic_ostream,值是pair类型。为了确定如何处理该operator<<调用,我们查找在此模板定义点可见的所有重载operator<<()以及参数关联命名空间中的重载(称为参数相关查找)。

当您使用struct pair时,pair的相关名称空间是::,因此ADL将找到您的::operator<<(std::ostream&, pair const&)。这种过载工作,是被选择的,一切都是快乐的。

当您使用std::pair时,pair的关联名称空间是std,没有一个operator<<()可以使用std::pair。因此出现了错误。

相反,您可以在自己的命名空间中创建自己的类型,为此可以添加重载的operator<<,这完全可以是您自己的类型(问题中的方式),也可以继承std中的类型。

代码语言:javascript
复制
struct pair : std::pair<string,string> {
    using std::pair<string,string>::pair;
};
std::ostream& operator<<(std::ostream&, my_pair const& ) {...}

或者,您可以不使用make_ostream_joiner。可以取代这一点:

代码语言:javascript
复制
std::copy(std::begin(pairs),
      std::end(pairs),
      std::experimental::make_ostream_joiner(std::cout, ", "));

在这方面:

代码语言:javascript
复制
const char* delim = "";
for (auto const& pair : pairs) {
    std::cout << delim << pair; // now, our point of definition does include
                                // our operator<<() declaration, we don't need ADL
    delim = ", ";
}
票数 2
EN

Stack Overflow用户

发布于 2019-06-09 01:15:17

是否有可能使流操作符在不污染std名称空间的情况下工作?

如果您愿意用一个copy替换您的transform,那么是的--使用从我在这里的回答获取的put_invocation,您可以使用:

代码语言:javascript
复制
std::transform(
    std::begin(pairs), std::end(pairs),
    std::experimental::make_ostream_joiner(std::cout, ", "),
    [](auto& p) {
        return put_invocation([&p = p](auto& os) {
            // adl works just fine here
            return os << p;
            // or `os << p.first << "=" << p.second;`
        });
    }
);

这应该优化到与注入std命名空间的版本完全相同的代码。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46454659

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档