【问题标题】:How to initialize a class data member which is a std::set with custom comparator如何使用自定义比较器初始化作为 std::set 的类数据成员
【发布时间】:2019-08-15 00:53:44
【问题描述】:

当它是类数据成员时,我不太确定使用自定义比较器初始化标准集的正确方法是什么。一旦我添加将列表迭代器插入集合的行,以下代码就会导致编译失败。我不知道为什么。

#include <list>
#include <set>
#include <iterator>

auto pred = [](auto const& v1, auto const& v2) {
                *v1 < *v2;
            };
using LstIter = std::list<int>::iterator;

class MaxStack {
public:
    MaxStack()
        :valLst(),
         valSet(pred)
    {}

    void push(int x) {
        valLst.push_back(x);
        LstIter it = std::prev(valLst.end());

        // this line causes compile failure
        valSet.insert(it);
    }

  private:
    std::list<int> valLst;
    std::set<LstIter, decltype(pred)> valSet;    
};

现在的问题是我忘记在 lambda 中输入 return。我不敢相信它是这样的,我已经看了 10 分钟的代码,但仍然没有看到它。

但是一个更有趣的问题是,如果那是错误的。为什么编译器在类构造函数代码期间没有出错。当我第一次尝试调用比较器时失败。编译器在构造集合时不应该检查比较器签名吗?

【问题讨论】:

  • 显示错误信息的准确和完整的文本。

标签: c++ class stl


【解决方案1】:
auto pred = [](auto const& v1, auto const& v2) {
                *v1 < *v2;
            };

将这个明显的胖手指修正为应有的样子:

auto pred = [](auto const& v1, auto const& v2) {
                return *v1 < *v2;
            };

导致 gcc 9 成功编译显示的代码。

【讨论】:

  • 天哪,我好尴尬。我一直想知道 10 分钟试图找出到底是什么问题。当然,它永远不会返回任何东西。
  • 另一方面。为什么编译器没有为构造函数代码出错。 set 的构造显然应该失败,预期的比较器签名应该返回一个 bool。
  • 因为std::set 是一个模板。模板方法在实际使用之前不会被实例化。这是模板如何工作的基础。构造函数代码中没有任何内容需要直接比较集合中的值,因此调用比较器的实际代码永远不会被实例化。但是,一旦您编写了实际必须执行的代码,std::set 的用于比较集合中的值的内部模板方法就会被实例化,编译器会发现一个小问题......(在我写完我的回答,下次请写一个新问题)。
  • 这是有道理的。谢谢你的解释。
【解决方案2】:

std::set 期望它的比较器返回一个bool。但是pred 是一个void 函数,它实际上并没有返回任何值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-01-19
    • 1970-01-01
    • 2021-12-15
    • 1970-01-01
    • 2022-01-28
    • 2021-06-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多