【发布时间】:2021-04-11 08:09:10
【问题描述】:
是的,我知道,我应该有一个复制品,但复制品制作起来很烦人。在我制作一个(并且可能给 clang 一个错误)之前,我想确保我对事物应该如何工作的理解是正确的。
-
MSVC:将
set::equal_range()作为{lower_bound(),upper_bound()}返回。 -
Clang:将
set::equal_range()作为{lower_bound(),upper_bound()-1}返回。 (使用 stdlib=libc++)——当然是我的例子。
我对过去 20 年 STL 编程的期望是 MSVC 是正确的。事实上,我正在编辑的代码是我 20 年前写的,它曾经在 clang 和 gcc 中工作,但现在只能在 MSVC 中工作(也许 gcc - 我还没有尝试过 - 我正在使用一些标题C++20 且仅在 stdlib=libc++ 和 MSVC 中,但不在 gcc 中)。
无论如何,我对 set::equal_range() 应该返回什么的假设是否正确?
好吧,看看吧:
Clang 与 -stdlib=libc++:https://godbolt.org/z/xfnasKa73
没有 -stdlib=libc++ 的 Clang:https://godbolt.org/z/5qYEj4MEd
如果您认为我的比较器是假的,请告诉我。
这里是测试代码:
#include <iostream>
#include <utility>
#include <set>
using namespace std;
struct Range : public pair< size_t, size_t >
{
using pair::pair;
bool operator < ( Range const & _r ) const
{
return second < _r.first;
}
};
typedef set< Range > vTySet;
int
main()
{
vTySet setRanges = {{0,0},{9,9},{10,10},{13,13},{32,32},{34,34},{61,61},{65,90},{101,101},{110,110}};
Range rngTest = { 97, 122 };
pair< vTySet::iterator, vTySet::iterator > pritEqualRange = setRanges.equal_range( rngTest );
size_t nDistEqualRange = distance( pritEqualRange.first, pritEqualRange.second );
pair< vTySet::iterator, vTySet::iterator > pritLowerUpper = { setRanges.lower_bound( rngTest ), setRanges.upper_bound( rngTest ) };
size_t nDistLowerUpper = distance( pritLowerUpper.first, pritLowerUpper.second );
cout << "nDistEqualRange:" << nDistEqualRange << "\n";
cout << "nDistLowerUpper:" << nDistLowerUpper << "\n";
}
【问题讨论】:
-
来自en.cppreference.com/w/cpp/container/set/equal_range:“第一个迭代器可以用lower_bound()获得,第二个用upper_bound()。”所以,也许minimal reproducible example会有所帮助澄清为什么你会得到这些值。
-
我无法想象 Clang 和 MS 会为
set::equal_range()返回不同的东西。很可能您的代码中有一些 UB,如果该 UB 的后果,您会看到差异。 -
如果您有自定义比较器,请检查它是否满足strict weak ordering requirements。
-
你的理解是正确的。如果 clang 为第二个迭代器返回
upper_bound()-1,那么您的代码有错误或 libc++ 有错误。您通常不会在标准库实现中发现错误,因此您真的需要创建一个重现问题的minimal reproducible example。 -
@DavidBien 它有时会发出警告的事实并不等同于保证它始终能够检测到它。
标签: c++ language-lawyer c++-standard-library