【问题标题】:What does std::includes actually do?std::includes 实际上是做什么的?
【发布时间】:2018-11-04 01:49:26
【问题描述】:

来自the standard,std::includes

如果[first2, last2) 为空或者[first2, last2) 范围内的每个元素都包含在[first1, last1) 范围内,则返回:true。 否则返回false

注意:因为这是在 [alg.set.operations] 下,范围必须排序

从字面上看,如果我们让R1=[first1, last1)R2=[first2, last2),这是评估:

∀a∈R2 a∈R1

但是,这并不是实际评估的内容。对于R1={1}R2={1,1,1}std::includes(R1, R2) 返回 false:

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> a({1});
    std::vector<int> b({1,1,1});

    // Outputs 'false'
    std::cout << std::boolalpha
        << std::includes(a.begin(), a.end(), b.begin(), b.end()) << '\n';
}

Live on Wandbox

这令人惊讶。我用 libstdc++ 和 libc++ 验证了它,但在我看来,这不太可能是标准库实现中的一个错误,因为它是算法库的一部分。如果这不是std::includes 应该运行的算法,那是什么?

【问题讨论】:

  • 这看起来像是缺陷报告的候选。我解释 [first2, last2) 范围内的每个元素都包含在 [first1, last1) 范围内,这意味着您需要 {1,1,1} 才能匹配 {1,1,1} 但它的措辞方式我可以看看为什么您可以期望您的案例有效。
  • 更多的是检查 R2 ⊆ R1
  • @Mgetz 但{1,1,1} 的每个元素都包含在{1} 中,因为它们都是1。对标准的字面理解允许两种解释恕我直言。
  • @NathanOliver 操作用语是每个元素,这意味着必须表示重复的元素,这是集合和列表之间的区别。标准是使用列表而不是集合。
  • @Mgetz 不是说“R2 中的每个元素都必须在 R1 中有对应的元素”,而是“R2 中的每个元素都必须包含在 R1 中”

标签: c++ language-lawyer c++17 stl-algorithm


【解决方案1】:

我在 cpplang slack 中发布了这个,Casey Carter responded:

标准中对算法的描述有缺陷。目的是确定 [if] needle 中的每个元素是否按顺序出现在大海捞针中。

[它实际执行的算法是:]“如果排序序列R1和R2的交集等于R2,则返回true”

或者,如果我们确定我们确定 subsequence 的含义:

返回:当且仅当 [first2, last2) 是 [first1, last1) 的子序列时才为真

link to Casey Carter's message

【讨论】:

    【解决方案2】:

    我相信您正在尝试检查您的示例中 a 是否包含 ba 不包含 bb 确实包含 a。如果你交换 ba 它将返回 true,因为 a 包含在 b 中。

    我希望我没有遗漏一些明显的东西。

    #include <algorithm>
    #include <iostream>
    #include <vector>
    
    int main() {
        std::vector<int> a({1});
        std::vector<int> b({1,1,1});
    
        // Outputs 'true'
        std::cout << std::boolalpha
            << std::includes(b.begin(), b.end(), a.begin(), a.end()) << '\n';
    }
    

    我通过玩弄算法了解到的是,当您输入includes(R2, R1) 时,它会检查R2 是否拥有R1 作为子组,如果是则返回true,如果不是则返回false。此外,如果未排序,则会引发错误:sequence not ordered

    【讨论】:

    • 我一开始也是这么想的,但在与贾斯汀(外部)讨论之后,很明显他的意思是“R2 中的每个元素”(即:1)都在 R1 中。我不能通过对标准的字面理解来说它是错误的,但这不是算法的意图
    • 哦,现在我明白了……我的错。英语不是我的强语言,有时我会错过重点。
    • “R2 中的每个元素” - 我将其理解为“所有三个 1”,而不仅仅是“1”。
    • @TuğberkKaanDuman 我认为 OP 并没有问算法实际上做了什么,但如果它做了什么就是标准所说的应该做什么。
    • 标题是What does std::includes actually do? 我观察并写下了我的经历。并非每个文档都是完美的,它们也是由人类编写的。现在我想它会好起来的。 @Slava
    【解决方案3】:

    和往常一样,阅读标准时,你必须阅读不成文的文字

    关注意图而不仅仅是字母。 (标准的措辞经常被认为是模糊的、不完整的、自我参照的或自相矛盾的。)

    阅读“28.7.6 Set operations on sorted structures [alg.set.operations]”部分的介绍:

    本小节定义了 sorted 上的所有基本集合操作 结构。他们还使用包含多个副本的多重集 等价元素。 集合操作的语义是 通过将 set_union() 定义为以标准方式推广到多集 包含每个元素的最大出现次数, set_intersection() 包含最小值,等等

    所以很明显includes的描述中的文字:

    返回:如果 [first2, last2) 为空或者如果 范围 [first2, last2) 包含在范围 [first1, last1) 中。 否则返回 false。

    必须忽略。您需要先验知道什么是多集操作,“包含”对于两个多集意味着什么,忽略描述并在脑海中重建显而易见的意图。 p>

    多集包含:

    A 包含在 B 中 iff A union B = B.

    这适用于集合或多重集合。

    【讨论】:

    • @n.m.谁赞成这个?其中 90% 是在以讽刺和过度臃肿的方式说“忽略标准”。然后它回答了最后 3 行中的问题。 IMO 这应该被删除,因为它会让任何从字面上理解它的人感到困惑
    • @M.M 你认为编译器作者是做什么的?他们做的是正确的,而不是标准所说的。当然要删,不符合你的世界观(std不能被批评?)。
    猜你喜欢
    • 1970-01-01
    • 2013-04-22
    • 2011-03-11
    • 2010-11-26
    • 2015-06-23
    • 2017-12-26
    • 2016-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多