C++14的异构比较

1,279次阅读
没有评论
C++14 的异构比较

在“IRResolver(STL set 重叠区间以及异构查询)”里面,提到过 std::set 在 c ++14 后可以进行异构查询。这部分其实可以展开讲讲,不仅限于上述文章的用法,也不仅限于 std::set。不过我们还是以std::set 为例,毕竟这个最典型也最常用。

数据库表中,有所谓的主键概念,任意两个记录的主键值不重复,因此我们通过查询主键就能找到唯一的一条记录。

在一些编程场景中,我们也有类似的需求。比如,一个小组有若干成员:

struct Member {
    uint32_t id;
    std::string name;
    uint32_t mutable age; // 为了在后面的集合中能够修改 age 字段,所以加 mutable
    //...
};

由于名字等其他字段都有可能重复,所以用工号 id 来惟一标识一个员工。我们用一个 set 来表示一个小组:

struct MemberCmp {bool operator() (const Member& l, const Member& r) const
    {return l.id < r.id;}
};

using Team = std::set<Member, MemberCmp>;

今天是 8 月 17 号,工号 1926 的童鞋生日了,年龄要增加一岁,我们自然希望这么写:


void age_inc(Team& t, uint32_t id)
{auto it = t.find(id);
    if (it != t.end()) {it->age++;}
}

在 c ++14 以前,这么写是编译不过的。因为 c ++14 之前,std::set::find是个普通的成员函数。它只接收当前模板类的 Key 类型作为参数。如果要实现这个功能,必须写成如下形式:

void age_inc(Team& t, uint32_t id)
{
    Member dummy;
    dummy.id = id;
    auto it = t.find(dummy);
    //...
}

且不说, 现实中 Member 可能是个比较复杂的结构,这样会导致一些性能问题,单纯从观感上来说,这么写绝对谈不上优雅。

好在 C ++14 之后,std::set::find增加了两个成员函数模板:

template< class K > iterator find(const K& x);
template< class K > const_iterator find(const K& x) const;

这样,find可以接收任意参数,只要该参数能与存储的 Key 类型通过比较器比较大小。容易想到,可以把 MemberCmp 改写成如下:

struct MemberCmp {bool operator() (const Member& l, const Member& r) const
    {return l.id < r.id;}
    bool operator() (uintt32_t id, const Member& r) const
    {return id < r.id;}
    bool operator() (const Member& l, uint32_t id) const
    {return l.id < id;}
};

然而这样还是存在编译错误。因为 C ++14 在这两个新函数里多了一条规定:只有当比较器中存在 Compare::is_transparent 类型定义时,这俩重载的模板函数才成立。至于为什么搞这么个规定,可以以看下这里:https://stackoverflow.com/questions/20317413/what-are-transparent-comparators

在 MemberCmp 中添加该类型定义,最终达成了我们期望的效果,见:https://godbolt.org/z/dzo43Yhqa

在”IRResolver(STL set 重叠区间以及异构查询)”中的用法,是 std::less<> 的void特化版本:https://zh.cppreference.com/w/cpp/utility/functional/less_void 原理是一样的。

正文完
 0
评论(没有评论)
验证码