C 深层懒惰的比较与优雅的语法
C++ deep lazy comparison with elegant syntax?
我有一个C 类,我需要定义一个比较器,该比较器应考虑几种潜在昂贵的方法的结果。我不想在集合中的所有对象中缓存这些方法的结果,因为优先级最高的标准更便宜,我希望最底部的非常昂贵的标准只能在极少数情况下触发。
。如果我的cmp()函数分别返回-1、0或1时,当第一个参数较小,相等或更大的第二个参数以及使用快捷方式的逻辑运算符可以保留整数,我可以很容易地写<</p>
int compare(const Class &rhs) const {
return cmp(expensive_method_a(), rhs.expensive_method_b()) ||
cmp(expensive_method_b(), rhs.expensive_method_b()) ||
...
}
不幸的是,我需要与&lt一起工作操作员,因此变得丑陋,昂贵且容易出错:
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() &&
(...
))))
}
或替代品,昂贵的较低,但仍然很丑:
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;
我已经阅读了有关STD ::的其他问题,但是如果我正确理解,TIE会在开始比较之前评估我的所有方法,我希望对这些论点进行懒惰的评估。
我考虑定义这样的预处理器宏:
#define CUT_COMPARE(a,b) { auto _x = (a); auto _y = (b); if (_x != _y) return (_x < _y); }
我会使用喜欢:
bool operator<(const Class &rhs) const {
CUT_COMPARE(expensive_method_a(), rhs.expensive_method_a());
CUT_COMPARE(expensive_method_b(), rhs.expensive_method_b());
...
}
希望牙套能将我的_x
和_y
封闭在私有范围中,但是a,clang++
抱怨_x
和_y
的多个定义。
围绕这个问题有更漂亮的方法吗?
您可以将要调用的所有成员函数转发到必要时通行的辅助模板:
:bool operator<(const Class& rhs) const {
return lazy_compare(*this, rhs, &Class::expensive_1,
&Class::expensive_2,
&Class::expensive_3);
}
lazy_compare
variadic函数将在必要时一次浏览一个指针到会员功能。基本情况仅为true
:
template <typename T, typename... MFs>
bool lazy_compare(const T&, const T&, MFs...) {
return true;
}
递归情况是弹出第一个指针到会员,看看我们是否可以停下来:
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...);
}
}
这是一个懒惰的比较对象。它拥有一些任意可呼叫的F
,当您在一对lazy_comp_f<?>
对象上调用cmp(lhs, rhs)
时,它会调用它,存储结果,并告诉您谁赢了:
template<class F>
struct lazy_comp_f {
F f;
template<class F1, class F2>
friend int cmp( lazy_comp_f<F1>const& lhs, lazy_comp_f<F2>const& rhs) {
auto l = lhs.f();
auto r = rhs.f();
// using cmp_ns::cmp; here
return cmp(l,r);
}
// ctors
lazy_comp_f(F&& fin):f(std::forward<F>(fin)) {}
lazy_comp_f(lazy_comp_f&&)=default;
lazy_comp_f(lazy_comp_f const&)=default;
template<class O, class=std::enable_if_t<std::is_convertible<O const&,F>>>
lazy_comp_f(lazy_comp_f<O> const&o):f(o.f){}
template<class O, class=std::enable_if_t<std::is_convertible<O,F>>>
lazy_comp_f(lazy_comp_f<O>&&o):f(std::move(o).f){}
};
template<class T>
using lazy_comp_t = lazy_comp_f<std::function<T()>>;
这是一个模板工厂功能助手,可扣除F
类型:
template<class F>
lazy_comp_f<std::decay_t<F>>
lazy_comp(F&& f){ return {std::forward<F>(f)}; }
这是一条懒惰的领带。它采用一系列用于生产昂贵物品的功能:
template<class...Fs, class R=std::tuple< lazy_comp_f<std::decay_t<Fs>>... >>
R lazy_tie( Fs&& fs ) {
return R( lazy_comp(std::forward<Fs>(fs)...) );
}
这是我们的基本cmp
。它使用<
并产生合理效率的cmp
操作。本地ADL查找可以在我们可以做得更好的情况下找到更好的超载:
template<class T, class U>
int cmp( T const& lhs, U const& rhs ) {
if (lhs < rhs) return -1;
if (rhs < lhs) return 1;
return 0;
}
现在努力允许cmp
的元组。两个帮助者:
namespace details {
template<class...Ts, class...Us>
int cmp(
std::index_sequence<>,
std::tuple<Ts...> const& lhs,
std::tuple<Us...> const& rhs
) {
return 0;
}
template<size_t I, size_t...Is,class...Ts, class...Us>
int cmp(
std::index_sequence<I, Is...>,
std::tuple<Ts...> const& lhs,
std::tuple<Us...> const& rhs
) {
// maybe using comp_ns::cmp here?
int c = cmp( std::get<I>(lhs), std::get<I>(rhs) );
if (c!=0) return c;
return cmp(std::index_sequence<Is...>{}, lhs, rhs);
}
}
,我们打电话给助手,防御无与伦比的LHS/RHS ARGS:
template<class...Ts, class...Us>
std::enable_if_t<sizeof...(Ts)==sizeof...(Us), int>
cmp(
std::tuple<Ts...> const& lhs,
std::tuple<Us...> const& rhs
) {
return details::cmp( std::make_index_sequence<sizeof...(Ts)>{}, lhs, rhs );
}
现在的问题是提供可可!
class
内部执行以下操作:
auto lazy_comparer() const
// std::tuple< lazy_comp_t<A>, lazy_comp_t<B>, lazy_comp_t<C> > in C++11
// where `A`, `B` and `C` are the return types of expensive_method_a etc
{
return lazy_tie(
[=]{ return expensive_method_a(); },
[=]{ return expensive_method_b(); },
[=]{ return expensive_method_c(); }
// etc
);
}
friend int cmp( Class const& lhs, Class const& rhs ) {
// using namespace cmp_ns::cmp here
return cmp( lhs.lazy_comparer(), rhs.lazy_comparer() ) < 0;
}
friend bool operator<( Class const& lhs, Class const& rhs ) {
return cmp(lhs,rhs)<0;
}
我们完成了吗?
请注意,该解决方案递归起作用。任何覆盖cmp
的人都会获得最佳版本,任何没有基于<
的人。如果某些子结构具有基于lazy
的cmp
,则被称为。
在C 14中,这是用低型擦除开销完成的。在C 11中,进行了一些毫无意义的分配(用于擦除类型) - 可以通过类似于代表的方法(轻度std::function
s)或其他微型量化的速度更快地制成。
使用的一些C 14个功能。它们易于在C 11中实现(除了auto
返回类型,我提供了解决方法)。
我会坚持使用 nice compare 方法,以此方式写:
int compare(const Class &rhs) const {
int cr;
cr = cmp(expensive_method_a(), rhs.expensive_method_a());
if (cr != 0) return cr;
cr = cmp(expensive_method_b(), rhs.expensive_method_b());
if (cr != 0) return cr;
...
}
这样,一旦一种方法给出不同的结果,它就会立即用正确的符号返回,并且只有在平等的情况下才能结束。
您可以在所有比较器中直接使用它:
bool operator<(const Class &rhs) const {
return compare(rhs) < 0;
}
bool operator<=(const Class &rhs) const {
return compare(rhs) <= 0;
}
bool operator>(const Class &rhs) const {
return compare(rhs) > 0;
}
bool operator>=(const Class &rhs) const {
return compare(rhs) >= 0;
}
bool operator==(const Class &rhs) const {
return compare(rhs) == 0;
}
bool operator!=(const Class &rhs) const {
return compare(rhs) != 0;
}
您可以像这样实现它:
bool operator<(const Class &rhs) const {
return expensive_method_a() < rhs.expensive_method_a() ||
expensive_method_b() < rhs.expensive_method_b() ||
..
expensive_method_N() < rhs.expensive_method_N() ||
}
它将在其中一种方法评估为true时立即返回,而无需评估其他方法。
- 1d 智能指针不适用于语法 (*)++
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 助记符和指向成员语法的指针
- 为什么比较运算符如此快速
- 有人能分解一下这个c++模板的语法吗
- C++避免重复声明的语法是什么
- QMetaObject invokeMethod的基于函数指针的语法
- 我可以使用 g++ 进行三种比较 (<=>) 吗?
- 比较字符数组
- 将模板化的类型与C++中的某些类/类型进行比较
- C++自定义比较函数
- 这个语法std::class<>{}(arg1, arg2) 在C++中是什么意思?
- 如何比较自定义类的std::变体
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- C++方法与Java的比较(从Java到C ++的语法)
- C 深层懒惰的比较与优雅的语法
- 比较类语法帮助中的对象;
- 比较参数包?扩展语法
- 在比较C++中的字符时,有没有特殊的语法
- c++复制赋值语法比较-哪个更好