C++深度懒惰与优雅的语法比较?

b0f*_*0fh 6 c++ c++11

我有一个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.

这有更漂亮的方法吗?

Bar*_*rry 4

您可以将要调用的所有成员函数转发到帮助程序模板,该模板将根据需要遍历它们:

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)