简体   繁体   English

我可以在没有底层容器的情况下使用std :: upper_bound吗?

[英]Can I use std::upper_bound without an underlying container?

I have a range of integers [start, end] and a non-decreasing monotonic function f(i) . 我有一系列整数[start, end]和一个非递减单调函数f(i) So conceptually, I have a non-decreasing sequence [f(start), f(start + 1), .. , f(end)] . 所以从概念上讲,我有一个非递减序列[f(start), f(start + 1), .. , f(end)] Can I use std::upper_bound on that sequence to find the first element i in the range that holds f(i) > some_value ? 我可以使用std::upper_bound该序列找到的第一个元素i在保存范围f(i) > some_value

Conceptually, I'd like something like this: 从概念上讲,我喜欢这样的事情:

std::upper_bound(start, end + 1, some_value, [&](int lhs, int rhs) { 
    return f(lhs) < f(rhs);
});

But this doesn't compile because start and end + 1 do not meet the requirements of forward iterators . 但这不会编译,因为startend + 1不符合forward迭代器的要求。

The short answer is yes, since std::upper_bound works on iterators, not on containers. 简短的回答是肯定的,因为std::upper_bound适用于迭代器,而不适用于容器。 But iterators themselves are instances of corresponding class (for example, std::vector<int>::iterator or whatnot). 但迭代器本身是相应类的实例(例如, std::vector<int>::iterator或whatnot)。

If you construct some specific class that will meet the requirements of ForwardIterator not being actually bound to some sort of container, while still meaning something (for example, if you want to generate your sequence procedurally), it should work just fine. 如果你构造一些特定的类来满足ForwardIterator的要求, ForwardIterator不是实际上绑定到某种容器,虽然仍然有意义(例如,如果你想在程序上生成序列),它应该可以正常工作。

Note that simple integer will not do the trick. 请注意,简单整数不会起作用。 On the other hand, a class, whose objects hold the value of your function for a particular argument value (with some additional batteries), will. 另一方面,一个类,其对象为特定参数值(带有一些额外的电池)保存函数的值,将会。

There are basically two answers: 基本上有两个答案:
Would it work by the standard or would it work with all practical implementations of the STL? 它是按照标准工作还是适用于STL的所有实际实现?

By the standard, as TC pointed out already, there are some strict requirements on iterators, especially that *it has to return a (possibly const) reference to value_type (which we would satisfy by returning the reference to a member of the iterator), but we also need that for it1 == it2 , *it1 and *it2 are references bound to the same object, which is only possible if we have a distinct object for every number in the range. 根据标准,正如TC已经指出的那样 ,对迭代器有一些严格的要求,特别是*it必须返回一个(可能是const)对value_type引用(我们通过返回对迭代器成员的引用来满足),但是我们还需要it1 == it2*it1*it2是绑定到同一个对象的引用,只有当我们为该范围内的每个数字都有一个不同的对象时才有可能。

If you want to do use this idea in practice, I don't believe any implementation of std::upper_bound or similar methods actually relies on this reference equality, so you could just use a class that encapsulates an integer as an iterator, only overloading the necessary methods . 如果你想在实践中使用这个想法,我不相信std::upper_bound或类似方法的任何实现实际上都依赖于这个引用相等,所以你可以只使用一个封装整数作为迭代器的类,只重载必要的方法 As far as I can see, boost::irange fulfills these requirements 据我boost::irangeboost::irange满足了这些要求

As you can see, this is not strictly standard-compliant, but I see no reason why any implementation of binary search should rely on such strong requirements for the iterator, if the underlying 'storage' is const anyway. 正如您所看到的,这不是严格符合标准的,但我认为没有理由为什么任何二进制搜索的实现都应该依赖迭代器的强大要求,如果底层的“存储”仍然是const。

No, not practically, but yes in practice, but no if you want to be practical. 不,不是实际,但在实践中是肯定的,但如果你想要实践则不是。

No 没有

upper_bound requires ForwardIterator . upper_bound需要ForwardIterator ForwardIterator requires that * returns an actual reference, and that if two iterators are equal then they refer to the same object. ForwardIterator要求*返回的实际值, 并且如果两个迭代相等则它们指代相同的对象。

Not practically 实际上并非如此

For a container-less iterator, this requires an insanely complex iterator that caches the values it returns in a shared global map of some kind. 对于无容器迭代器,这需要一个非常复杂的迭代器,它将它返回的值缓存在某种共享的全局映射中。 To make it half practical, note that the iterator requirements say very little about the lifetime of said reference; 为了使它变得一半实用,请注意迭代器要求对所述参考的寿命几乎没有说明; so you'd want to reference count and destroy said values as the iterators in question cease to exist. 所以你想要引用计数并销毁所述值,因为有问题的迭代器不再存在。

Such a solution requires synchronization, global state, and is significantly more expensive and complex than something like boost::integer_range . 这样的解决方案需要同步,全局状态,并且比boost::integer_range更加昂贵和复杂。 No sane person would write this except as an exercise demonstrating why the standard needs to be fixed. 没有理智的人会写这个,除非作为演示标准需要修复的练习。

But yes in practice 但是在实践中是的

No sane implementation of upper_bound actually requires that the iterators in question are full-scale forward iterators, barring one that does full concept-checks to validate against the standard (and not against what the actual algorithm needs). 没有合理的upper_bound实现实际上要求所讨论的迭代器是完整的前向迭代器,除非进行完整的概念检查以验证标准(而不是实际算法需要的)。 Input iterators with stability on the values returned almost certainly does it. 输入迭代器在返回的值上具有稳定性,几乎可以肯定。 There is no such concept in the C++ standard, and forward iterator is the weakest iterator category in the standard that satifies it. 在C ++标准中没有这样的概念,并且前向迭代器是标准中最弱的迭代器类别,它满足它。

This problem, of effectively demanding iterators be backed by containers, is a flaw in the standard in my opinion. 这个问题,有效地要求迭代器由容器支持,在我看来是标准的一个缺陷。 Container-free iterators are powerful and useful, except they rarely technically work in standard containers. 无容器迭代器功能强大且有用,除非它们在技术上很少在标准容器中工作。

Adding new iterator categories has proved problematic, because there is little way to do it without breaking existing code. 添加新的迭代器类别已经证明是有问题的,因为在不破坏现有代码的情况下几乎没有办法。 They looked into it for contiguous iterators, and wrote it off as impractical (I don't know all the details of what they tried). 他们调查它是为了连续的迭代器,并把它写下来是不切实际的(我不知道他们尝试过的所有细节)。

Adding new iterator concepts that are not backed by tags is more possible, but probably will have to wait until concepts are part of the C++ language and not just the standard; 添加没有标记支持的新迭代器概念是更有可能的,但可能必须等到概念是C ++语言的一部分而不仅仅是标准; then experimenting with adding new concepts becomes something you can specify in C++ instead of in standardese, which makes it far easier. 然后尝试添加新概念成为您可以在C ++而不是标准中指定的东西,这使得它更容易。

But no if you want to be practical 但不,如果你想要实用

This does, however, result in an ill-formed program, no diagnostic required. 但是,这会导致程序格式错误,无需诊断。 So consider if it is worth it; 所以考虑是否值得; it may actually be easier to reimplement upper_bound than maintain a program whose every excution is undefined behavior, and every compile at the mercy of a compiler upgrade. 实际上,重新实现upper_bound比维护每个执行都是未定义行为的程序更容易,并且每次编译都受编译器升级的支配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我可以合法地使用带有重载operator()的结构作为比较std :: upper_bound吗? - Can I legally use a struct with overloaded operator() as Compare for std::upper_bound? 为什么我不能重载传递给std :: upper_bound的比较器 - Why can't I overload this comparator that I pass to std::upper_bound C ++ STL集合:我可以使用upper_bound()来找到数字与集合元素的最小差吗? - C++ STL set: Can I use upper_bound() to find the minimum difference of a number with the elements of the set? 这是使用std :: upper_bound和std :: lower_bound的正确方法吗? - is this right way to use std::upper_bound and std::lower_bound? 使用STL Container设置upper_bound - using STL Container set upper_bound std::map::upper_bound 与 std::upper_bound 性能 - std::map::upper_bound vs std::upper_bound performance 如何使用 lower_bound/upper_bound 从 std::set 获取索引号? - How to use lower_bound/upper_bound to get index number from std::set? 关于std :: lower_bound和std :: upper_bound的问题 - Questions about std::lower_bound and std::upper_bound std :: lower_bound和std :: upper_bound的基本原理? - rationale for std::lower_bound and std::upper_bound? 我需要将什么类型的 std::function 分配给 std::upper_bound 或 std::lower_bound - What type of std::function to I need to be able to assign it to either std::upper_bound or std::lower_bound
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM