我有一个C++类,我需要定义一个比较器,它应该考虑几种可能很昂贵的方法的结果.我不想为我的集合中的所有对象缓存这些方法的结果,因为具有最高优先级的标准更便宜,并且我希望底部非常昂贵的标准仅在极少数情况下触发.
如果我有一个cmp()函数分别返回-1,0或1,当第一个参数小于,等于或大于第二个时,并且使用保存整数的快捷逻辑运算符,我可以轻松地写
int compare(const Class &rhs) const {
return cmp(expensive_method_a(), rhs.expensive_method_b()) ||
cmp(expensive_method_b(), rhs.expensive_method_b()) ||
...
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,我需要使用<运算符,因此它变得丑陋,昂贵且容易出错:
bool operator<(const Class &rhs) const {
return expensive_method_a() < rhs.expensive_method_a() ||
(expensive_method_a() == rhs.expensive_method_a() &&
(expensive_method_b() < rhs.expensive_method_b() ||
(expensive_method_b() == rhs.expensive_method_b() &&
(...
))))
}
Run Code Online (Sandbox Code Playgroud)
或者,成本更低但仍然相当难看:
bool operator<(const Class &rhs) const {
auto al = expensive_method_a(), ar = rhs.expensive_method_a();
if (al != ar) return al < ar;
auto bl = expensive_method_b(), br = rhs.expensive_method_b();
if (bl != br) return bl < br;
Run Code Online (Sandbox Code Playgroud)
我读过有关的std ::领带这个其他的问题,但如果我理解正确的话,领带会开始前comparaison我所有的方法评估,我想这些参数来进行评估懒惰.
我考虑过定义一个预处理器宏,例如:
#define CUT_COMPARE(a,b) { auto _x = (a); auto _y = (b); if (_x != _y) return (_x < _y); }
Run Code Online (Sandbox Code Playgroud)
我会使用像:
bool operator<(const Class &rhs) const {
CUT_COMPARE(expensive_method_a(), rhs.expensive_method_a());
CUT_COMPARE(expensive_method_b(), rhs.expensive_method_b());
...
}
Run Code Online (Sandbox Code Playgroud)
希望括号可以包围我_x和_y私人范围,但唉,clang++抱怨有多种定义_x和_y.
这有更漂亮的方法吗?
您可以将要调用的所有成员函数转发到帮助程序模板,该模板将根据需要遍历它们:
bool operator<(const Class& rhs) const {
return lazy_compare(*this, rhs, &Class::expensive_1,
&Class::expensive_2,
&Class::expensive_3);
}
Run Code Online (Sandbox Code Playgroud)
根据需要,可变lazy_compare参数函数将一次遍历这些指向成员函数的指针。基本情况只是true:
template <typename T, typename... MFs>
bool lazy_compare(const T&, const T&, MFs...) {
return true;
}
Run Code Online (Sandbox Code Playgroud)
递归的情况是弹出第一个指向成员的指针,看看我们是否可以停在那个指针处:
template <typename T, typename R, typename... MFs>
bool lazy_compare(const T& left, const T& right, R (T::*mf)() const, MFs... rest) {
R vleft = (left.*mf)(), vright = (right.*mf)();
if (vleft != vright) {
return vleft < vright;
}
else {
return lazy_compare(left, right, rest...);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
536 次 |
| 最近记录: |