使用 ostream_iterator 将 STL Map 的内容写入输出流

发布于 2025-01-10 09:23:43 字数 2181 浏览 3 评论 0 原文

我有一个 map 对象,我想使用 ostream_iterator 将其内容写入屏幕或文件。我重载了输出运算符 (operator<<),以便它可用于将 pair 类型的对象写入输出流,但是当我尝试编译代码,但收到以下错误消息:

错误:与“operator<<”不匹配(操作数类型是 'std::ostream_iterator >::ostream_type' {又名 'std::basic_ostream'} 和 'const std::pair')
207 | 207 *_M_stream << __值;

我最终使用 for_each 函数来编写内容,但我很好奇是否有一种方法可以使用流迭代器来完成这项工作。 以下是代码摘录:

typedef map<string, int>::value_type map_value_type;

ostream &operator<<(ostream &out, const map_value_type &value) {
  out << value.first << " " << value.second;
  return out;
}

int main() {
  map<string, int> m;

  // code to fill the map

  // The following works with no problem
  for_each(m.begin(), m.end(), [](const map_value_type &val) { cout << val << endl; });

  // This line will not compile
  copy(m.begin(), m.end(), ostream_iterator<map_value_type>(cout, "\n"));
}

奇怪的是,当我强制编译器给出上面的 operator<< 函数中使用的参数的完整类型名称时,它们与错误消息中提到的类型完全匹配,但由于某种原因编译器无法识别使用它。我使用 g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 和 -std=gnu++17 标志,但 Visual Studio 编译器(cl.exe 版本 19.29.30140) 会给出相同的错误。

我还对 operator<< 尝试了以下操作,但没有成功:

ostream &operator<<(ostream &out, const pair<string, int> &val);
ostream &operator<<(ostream &out, const pair<const string, int> &val);
ostream &operator<<(ostream &out, pair<const string, int> &val);
ostream &operator<<(ostream &out, pair<string, int> val);
ostream &operator<<(ostream &out, pair<const string, int> val);

template <typename key, typename value>
ostream &operator<<(ostream &out, const pair<key, value> &val) { ... }

上述所有函数都适用于 for_each 方法,但它们都不适用于 ostream_iterator

我错过了什么?!

I have a map<string, int> object and I want to use ostream_iterator to write the contents of it to the screen or a file. I have overloaded output operator (operator<<) so that it can be used to write objects of type pair<const string, int> to an output stream, but when I try to compile the code I get the following error message:

error: no match for ‘operator<<’ (operand types are
‘std::ostream_iterator<std::pair<const
std::__cxx11::basic_string, int> >::ostream_type’ {aka
‘std::basic_ostream’} and ‘const std::pair<const
std::__cxx11::basic_string, int>’)
207 | *_M_stream << __value;

I ended up using for_each function to write the contents, but I was curious to find out if there's a way to use the stream iterator to do the job.
Here's an excerpt of the code:

typedef map<string, int>::value_type map_value_type;

ostream &operator<<(ostream &out, const map_value_type &value) {
  out << value.first << " " << value.second;
  return out;
}

int main() {
  map<string, int> m;

  // code to fill the map

  // The following works with no problem
  for_each(m.begin(), m.end(), [](const map_value_type &val) { cout << val << endl; });

  // This line will not compile
  copy(m.begin(), m.end(), ostream_iterator<map_value_type>(cout, "\n"));
}

Curiously, when I force the compiler to give the full type names of parameters used in the operator<< function above, they exactly match the types mentioned in the error message, but for some reason compiler does not recognize to use it. I'm using g++ (Ubuntu 9.3.0-17ubuntu1~20.04) with -std=gnu++17 flag, but Visual Studio compiler (cl.exe version 19.29.30140) will give the same error.

I have also tried the following for operator<< without any success:

ostream &operator<<(ostream &out, const pair<string, int> &val);
ostream &operator<<(ostream &out, const pair<const string, int> &val);
ostream &operator<<(ostream &out, pair<const string, int> &val);
ostream &operator<<(ostream &out, pair<string, int> val);
ostream &operator<<(ostream &out, pair<const string, int> val);

template <typename key, typename value>
ostream &operator<<(ostream &out, const pair<key, value> &val) { ... }

All of the above mentioned functions work with the for_each approach, but none of them work with ostream_iterator.

What am I missing?!

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

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

发布评论

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

评论(1

铃予 2025-01-17 09:23:43

std::ostream_iterator 在内部使用 <<

当为类型实例化时,<< 将仅通过从实例化点进行依赖于参数的查找来查找 operator<< 重载,而不是通过正常的非限定名称抬头。

对于 pair 类型(map 的元素类型),参数相关查找所考虑的命名空间仅为 :: std,因为其中定义了pairstring。您在全局命名空间中的重载将不会被考虑。

如果您有一个类似 pair 的类型,其中 MyClass 是您在全局范围内自己定义的类,则重载将起作用,因为全局命名空间范围将成为参数相关查找的一部分,作为模板参数 MyClass 的关联命名空间。

使用 lambda 的版本之所以有效,是因为它也从 lambda 的定义点进行正常的非限定查找,从而在全局命名空间中找到重载。

不幸的是,据我所知,对于不依赖于自定义类型的标准库容器专业化,没有符合标准的方法来重载运算符<<,因此它将是通过 ADL 例如通过 std::ostream_iterator 找到。

符合标准是问题所在,因为标准禁止将 operator<< 重载添加到命名空间 std 中,否则从技术上讲可以解决该问题。

std::ostream_iterator uses << internally.

When it is instantiated for a type, << will find operator<< overloads only via argument-dependent lookup from the point of instantiation, not via normal unqualified name lookup.

For type pair<const string, int> (the element type of map<string, int>) the namespace considered for argument-dependent lookup is only ::std, because both pair and string are defined in it. Your overload in the global namespace will not be considered.

If you had a type like pair<MyClass, int>, where MyClass is a class you defined yourself at global scope, the overload would work, because then the global namespace scope would be part of argument dependent lookup as associated namespace of the template argument MyClass.

The version using a lambda works because it does normal unqualified lookup from the point of definition of the lambda as well, which finds the overload in the global namespace.

Unfortunately, as far as I am aware, there is no standard-conform way to overload operator<< for a standard library container specialization which doesn't depend on a custom type, so that it will be found via ADL e.g. by std::ostream_iterator.

Standard-conform is the issue, since the standard forbids adding overloads of operator<< to namespace std, which otherwise would technically solve the issue.

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