【问题标题】:Implementation difference when using std::find on a std::map between libc++ and libstdc++在 libc++ 和 libstdc++ 之间的 std::map 上使用 std::find 时的实现差异
【发布时间】:2019-10-25 09:43:27
【问题描述】:

我试图向一些同事总结std::find 的工作原理,我想向他们展示在std::map 上使用它是多么棘手(以及为什么他们不应该),所以我开始摆弄编译器探险家。

我想我遇到了libc++libstdc++ 之间的实现差异,因为下面的 sn-p 在前者上编译

#include <string>
#include <map>

int main (){
  std::map<std::string, int> myMap;

  myMap["string1"] = 100;

  std::map<std::string, int>::value_type element("string1", 100);

  auto it = std::find(myMap.begin(), myMap.end(), element);
}

但编译失败,后者产生以下错误

error: no matching function for call to 'find'
  auto it = std::find(myMap.begin(), myMap.end(), element);
            ^~~~~~~~~
/opt/compiler-explorer/gcc-9.2.0/lib/gcc/x86_64-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/streambuf_iterator.h:373:5: note: candidate template ignored: could not match 'istreambuf_iterator' against '_Rb_tree_iterator'
    find(istreambuf_iterator<_CharT> __first,
    ^
1 error generated.

所以我很困惑,我想知道这两者中的哪一个是理想的行为。编译器资源管理器链接:

【问题讨论】:

  • 你必须包含标题,那么问题是什么?
  • @VladfromMoscow 我想唯一的问题是编译器错误似乎表明参数不匹配“无法将'istreambuf_iterator'与'_Rb_tree_iterator'匹配”
  • @SPD 编译器明确表示找不到名称 std::find。
  • @VladfromMoscow 我知道。我只是在说明模板错误经常令人困惑的事实,这是一个很好的例子。在这种情况下,编译器最好只抑制“无法匹配'istreambuf_iterator' ...”这一行——这会更直观,而且我们很可能根本不会花时间在这篇文章上。
  • @SPD 起初编译器没有找到该函数。找到函数后,编译器可以判断其参数是否有效。

标签: c++ c++11 libstdc++ libc++


【解决方案1】:

您必须#include &lt;algorithm&gt;,如文档中的here

你很幸运,一个库为你隐式包含了那个头文件,但你真的不应该依赖它。

【讨论】:

  • 为什么像std::stringstd::map 这样的标准std 类应该依赖于#include 其头文件的算法?有什么想法吗?
  • 也许字符串实现决定在其方法之一中使用 std::find 。这是一个实现细节,不用担心,也不要依赖它。
【解决方案2】:

如果您查看 C++ 标准,您会发现在使用标头 &lt;map&gt; 时,C++ 标准要求包含的唯一标头是标头 &lt;initializer_list&gt;。这同样适用于标题&lt;string&gt;。这是唯一需要包含的标头是&lt;initializer_list&gt;

允许实现在&lt;map&gt;&lt;string&gt; 中包含任何其他标头。但是它是由实现定义的。

当使用标题&lt;iostream&gt; 时,例如标题&lt;string&gt; 会发生类似的情况。一些实现在标题&lt;iostream&gt; 中包含标题&lt;string&gt;,其他实现则不这样做。

因此,如果标准未明确指定这些标头包含在其他使用的标头中,则您始终应包含所有必需的标头。

【讨论】:

  • [res.on.headers] 表示“C++ 头文件可能 包含其他 C++ 头文件。”这实际上是 impl def 吗?
  • @L.F.是的,它是实现定义的。这取决于实现将包含哪些标头。
  • 你是怎么得出这个结论的? 可能 != 定义的实现。它也可以是未指定的行为。特别是,Index of implementation-defined behavior 没有列出它。
  • @L.F.可能意味着定义的实现,因为它没有指定实现将包含哪些确切的标头。
  • ???我试图争辩说这是未指定的行为,而不是实现定义的行为。 (并不是说这种区别与非学究的人有关;-)
猜你喜欢
  • 2018-05-10
  • 2012-02-18
  • 2017-04-07
  • 1970-01-01
  • 1970-01-01
  • 2018-12-20
  • 2011-11-21
  • 2013-11-12
  • 1970-01-01
相关资源
最近更新 更多