将std :: set与自定义比较器进行比较

时间:2017-01-23 14:12:40

标签: c++ c++11 templates

我正在尝试使用std::tie来实现operator<,以便创建包含集合的结构图。没有模板的相同代码似乎有效。我从我的编译器获取此消息代码:

  

/ usr / include / c ++ / 4.8 / bits / stl_algobase.h:888:错误:operator<不匹配(操作数类型为const SiPa<int, int>const SiPa<int, int>

if (*__first1 < *__first2)
              ^

如果我评论myMap.insert({akey, true});行,则会编译所有内容。

任何提示?

template<class I = int, class S = int>
struct SiPa
{
    I i;
    S s;
};

template<class I = int, class S = int>
struct SiPaComparator
{
    bool operator() (const SiPa<I, S>& first, const SiPa<I, S>& second) const
    {
        return std::tie(first.i, first.s) < std::tie(second.i, second.s);
    }
};

template<class I = int, class S = int>
struct AKey
{
    typedef std::set< SiPa<I, S>, SiPaComparator<I,S> > SetType;
    SetType keySet;
    I keyI;
};

template<class I = int, class S = int>
struct AKeyComparator
{
    bool operator() (const AKey<I, S>& first, const AKey<I, S>& second) const
    {
        return std::tie(first.keySet, first.keyI) < std::tie(second.keySet, second.keyI);
    }
};

int main()
{
    AKey<int,int> akey;

    std::map<AKey<int,int>, bool, AKeyComparator<int,int>> myMap;
    myMap.insert({akey, true});
}

3 个答案:

答案 0 :(得分:2)

您需要添加运算符&lt;对于struct SiPa,std :: map需要它

template<class I = int, class S = int>
struct SiPa {
  I i;
  S s;

  bool operator<(const SiPa<I, S> &ref) {
    return i < ref.i && s < ref.s;
  }
};

答案 1 :(得分:2)

通常,mapset上的比较器有状态。在比较两个不同的setmap时,没有明显的方法可以选择使用哪个。

因此,在通过set比较不同的map<时,您会得到std::lexographical_compare而没有Compare参数,该参数使用< 。 (注意,对于不是来自同一数组的对象的set指针,这很糟糕)

struct order_by_tie {
  template<class Lhs, class Rhs,
    class=std::enable_if_t<
      std::is_base_of<order_by_tie, Lhs>::value
      && std::is_base_of<order_by_tie, Rhs>::value
    >
  >
  friend bool operator<(Lhs const& lhs, Rhs const& rhs) {
    return as_tie(lhs) < as_tie(rhs);
  }
};

order_by_tie旨在继承自。它使用ADL(参数依赖查找)在其后代类上启用<,通过调用每一侧的自由函数as_tie然后执行<来实现。

我们按如下方式使用它:

template<class I = int, class S = int>
struct SiPa:order_by_tie
{
  I i;
  S s;
  friend auto as_tie( SiPa const& self ) {
    return std::tie(self.i, self.s);
  }
};

template<class I = int, class S = int>
struct AKey:order_by_tie
{
  typedef std::set< SiPa<I, S>, SiPaComparator<I,S> > SetType;
  SetType keySet;
  I keyI;
  friend auto as_tie( AKey const& self ) {
    return std::tie(self.keySet, self.keyI);
  }
};

然后

std::map<AKey<int,int>, bool> myMap;

作品。

as_tie使用C ++ 14,因为替代方案很烦人。您可以为C ++ 11添加-> decltype(std::tie( blah, blah ))(重复自己)。

答案 2 :(得分:1)

根据http://www.cplusplus.com/reference/set/set/operators/

  

其他操作也使用运算符==和&lt;在内部比较元素,表现得好像执行了以下等效操作:

     

请注意,这些操作都不考虑两个容器的内部比较对象

所以std::set<SiPa<I, S>, SiPaComparator<I,S>>的比较完成了

operator < (const SiPa<I, S>&, const SiPa<I, S>&)

而不是

SiPaComparator<I, S>{}

解决方法是定义operator <