【问题标题】:Overload custom comparator to std::map将自定义比较器重载到 std::map
【发布时间】:2017-04-01 01:11:47
【问题描述】:

我正在尝试解决this problem。我想出了这个解决方案:

typedef unordered_map<string, double> stockDictType;

class StockTicker {
  class Comparator {
  public:
    inline bool operator() (const string &a, const string &b) const {
      return stocksDict.at(a) < stocksDict.at(b);
    }
  };

  stockDictType stocksDict;

  map<string, stockDictType::iterator, Comparator> stocksTicker; // this is where I need a custom comparator method

  int tickerSize;

public:
  StockTicker(int k): tickerSize(k) {}

  // some other methods
};

很明显,这无法编译:StockTicker::stocksDict 不是静态成员。现在我不能这样做,因为我可能需要StockTicker 类的多个实例。

std::map 使用严格的比较器函数参数定义(std::map 只会传入要比较的键),所以我不能重载它来传递对StockTicker 类的当前实例的引用(我可以用来通过公共获取器访问StockTicker::stocksDict

我从 this SO questionsubsequent answer 获得灵感来做到这一点:

typedef unordered_map<string, double> stockDictType;

class StockTicker {
  class Comparator {
  public:
    stockDictType &_stockDictRef;

    explicit Comparator(stockDictType &stocksDict): _stockDictRef(stocksDict) {}

    inline bool operator() (const string &a, const string &b) const {
      return _stockDictRef.at(a) < _stockDictRef.at(b);
    }
  };

  stockDictType stocksDict;
  map<string, stockDictType::iterator, Comparator> stocksTicker(Comparator{stocksDict});
  int tickerSize;

public:
  StockTicker(int k): tickerSize(k) {}

  void addOrUpdate(string name, double price) {
    stocksDict[name] = price;
    stocksTicker.at(name) = stocksDict.find(name);
  }

  vector<stockDictType::iterator> top() {
    vector<stockDictType::iterator> ret(tickerSize);

    auto it = stocksTicker.begin();
    for(int i = 0; i < tickerSize; i++, it++)
      ret[i] = it->second;

    return ret;
  }
};

这也不会编译。我在StockTicker::addOrUpdate()StockTicker::top() 方法中得到了这个kind of errorerror: '((StockTicker*)this)-&gt;StockTicker::stocksTicker' does not have class type.

我也尝试了很多其他的东西(比如在StockTicker 类本身中声明一个公共比较器方法并尝试将它的函数指针传递给std::map。这也失败了;StockTicker::stocksTicker 之前被声明过比较器方法会,编译器会抱怨)。

关于如何解决此问题的任何想法?

【问题讨论】:

    标签: c++ c++11 overloading stdmap custom-compare


    【解决方案1】:
     std::map<std::string, stockDictType::iterator, Comparator> stocksTicker(Comparator(stocksDict));
    

    这定义了一个名为stocksTicker 的成员函数,它接受Comparator 类型的stocksDict 参数并返回std::map

    std::map<std::string, stockDictType::iterator, Comparator> stocksTicker{Comparator{stocksDict}};
    

    这定义了一个成员变量stocksTicker,默认情况下使用Comparator初始化,而Comparator又使用成员变量stocksDict初始化。

    我假设你想要第二个。

    您的语法介于两者之间。无论您对此感到困惑的编译器。

    Live example

    您应该StockTicker(StockTicker &amp;&amp;)=deleteStockTicker&amp; operator=(StockTicker &amp;&amp;)=delete,因为包含对其所在类的引用的映射不能安全移动或复制。

    在这里产生一个有效的移动是很棘手的。我怀疑 C++17 节点拼接可能会做到这一点。您可能必须嵌入 std::shared_ptr&lt;stocksDict*&gt;(是的,指向指针的共享指针),并使用 .key_comp 在目标中重新安装 stocksDict

    【讨论】:

    • 这非常有效。不过,最后两段对我来说毫无意义。我在哪里可以找到更多解释?
    • @Quirk 如果你有一个struct foo 并且在foo 中你存储一个指针返回到结构,默认的移动/复制操作符将以复制的结尾-to foo 包含一个返回到原始 foo 的指针。像这样:struct foo { foo* self; foo():self(this) {} }; foo f1; foo f2=f1; 现在是f2.self == &amp;f1;,这通常不是你想要的。地图中的比较器实际上有一个指向包含地图的对象的指针(嗯,指向对象中的成员字段)。最后一段第二段说解决这个问题的简单方法是禁止移动/复制。
    • 谢谢!我也想知道为什么这不起作用:std::map&lt;std::string, stockDictType::iterator, Comparator&gt; stocksTicker((Comparator(stocksDict))); 根据this answer,这应该绕过语法问题,不是吗?
    • @quirk () 不允许在类的内联变量 init 中使用。使用{}s
    猜你喜欢
    • 2013-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多