规范关系运算符(==,<,...) [英] Canonical relation operators (==,<,...)

查看:135
本文介绍了规范关系运算符(==,<,...)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑一个结构(例如:几个成员的愚蠢夸张),这些结构都实现一定的关系R(例如<):

Consider a struct (as in: stupid aggergation of several members) with members that all implement a certain relation R (e.g. <):

struct X {
  A a;
  B b;
};

对于大多数运算符,X R X存在一个 canonical 定义.例如:

For most operators there exists a canonical definition for X R X. For instance:

bool operator<(X const& x1, X const& x2) {
  if ((x1.a < x2.a) || (x2.a < x1.a)) // I intentionally did not use != here
    return x1.a < x2.a;
  if ((x1.b < x2.b) || (x2.b < x1.b))
    return x1.b < x2.b;
  return false;
}

这对所有运算符来说都是很无聊的事情,特别是如果您有相当多的成员而不仅仅是一个这样的结构.

This is pretty boring to do for all operators, especially if you have quite some members and not only one such struct.

如您所见,X上的operator<仅依赖其成员类型(AB)中的operator<,而没有使用bool || bool.

As you can see, operator< over X only relies on operator< of its member types (A,B) besids the use of bool || bool.

是否有一种方法可以通用地指定此类运算符(通过模板或内置插件?). Boost不是一种选择(但是,如果能够做到这一点将很有趣).

Is there a way to specify such operators generically (via templates or builtins?). Boost is not an option (but it would be interesting if it can do this, nevertheless).

如果您可以指定成员的评估顺序(对于速度),那就更好了.

It would be even greater if you could specify the evaluation order of the members (for speed).

编辑,我想这个问题是C ++ 03,否则我可以使用std::tuple.

Edit This question considers C++03, as otherwise you could use std::tuple, I guess.

推荐答案

显然没有非增强解决方案,所以我酝酿了一些模板魔术,如果有人遇到同样的问题,我将其发布为答案;

As apparently there is no non-boost solution, I brewed up some template magic, which I am posting as an answer in case somebody has the same problem;

版本1:显式参数

namespace multioperator {

  enum LazyBool {
    LB_false = false,
    LB_true = true,
    LB_undefined
  };

  template <typename Cmp, typename B> class Operator {
    public:
      typedef typename Cmp::first_argument_type A;
    private:
      A const& a1;
      A const& a2;
      B const& b;
    public:
      Operator(A const& a1, A const& a2, B const& b)
        : a1(a1), a2(a2), b(b) {
      }
      operator bool() const {
        switch (static_cast<LazyBool>(Cmp(a1,a2))) {
          case LB_false:
            return false;
          case LB_true:
            return true;
          case LB_undefined:
          default: // g++ does not understand that we have all branches :(
            return static_cast<bool>(b);
        }
      }
  };

  template <typename Fn> class BinaryFunctorMonad {
    public:
      typedef typename Fn::first_argument_type first_argument_type;
      typedef typename Fn::second_argument_type second_argument_type;
      typedef typename Fn::result_type result_type;
    private:
      first_argument_type const& a;
      second_argument_type const& b;
    public:
      BinaryFunctorMonad(first_argument_type const& a, second_argument_type const& b)
        : a(a), b(b) {
      }
      operator result_type() {
        return Fn()(a,b);
      }
  };

  enum CmpSymmetry {
    CS_Symmetric = false,
    CS_Asymmetric = true
  };

  template <typename Cmp, CmpSymmetry asymmetric> class LazyCmp {
    public:
      typedef typename Cmp::first_argument_type first_argument_type;
      typedef typename Cmp::first_argument_type second_argument_type;
      typedef LazyBool result_type;
      LazyBool operator()(first_argument_type const& a1, second_argument_type const& a2) const {
        if (Cmp(a1,a2))
          return LB_true;
        if (asymmetric && Cmp(a2,a1))
          return LB_false;
        return LB_undefined;
      }
  };

  template <typename A, typename B> struct MultiLess {
    typedef
      Operator<
        BinaryFunctorMonad<
          LazyCmp<
            BinaryFunctorMonad<std::less<A> >,
            CS_Asymmetric>
        >, B>
      Type;
  };

  template <typename A, typename B> struct MultiEqual {
    typedef
      Operator<
        BinaryFunctorMonad<
          LazyCmp<
            BinaryFunctorMonad<std::equal_to<A> >,
            CS_Symmetric>
        >, B>
      Type;
  };

}

template <typename A, typename B> typename multioperator::MultiLess<A,B>::Type multiLess(A const& a1, A const& a2, B const& b) {
  return typename multioperator::MultiLess<A,B>::Type(a1,a2,b);
}

template <typename A, typename B> typename multioperator::MultiEqual<A,B>::Type multiEqual(A const& a1, A const& a2, B const& b) {
  return typename multioperator::MultiEqual<A,B>::Type(a1,a2,b);
}
// example: multiLess(a1,a2,multiLess(b1,b2,multiLess(c1,c2,false)))

免责声明:我知道BinaryFunctorMonad有点用词不当,我只是想不出更好的办法.

Disclaimer: I know BinaryFunctorMonad is a slight misnomer, I just couldn't come up with something better.

版本2:继承

template <typename A, typename Chain> class MultiComparable {
  private:
    A const& a;
    Chain chain;
  public:
    typedef MultiComparable MultiComparableT;
    MultiComparable(A const& a, Chain chain) : a(a), chain(chain) {}
    bool operator<(MultiComparable const& as) {
      if (a != as.a)
        return a < as.a;
      return chain < as.chain;
    }
    bool operator==(MultiComparable const& as) {
      if (a != as.a)
        return false;
      return chain == as.chain;
    }
};

template <typename A, typename Chain> MultiComparable<A,Chain> multiComparable(A const& a, Chain chain) {
  return MultiComparable<A,Chain>(a,chain);
}

//example:
struct X : MultiComparable<int,MultiComparable<float,bool> > {
  int i;
  float f;
  X() : MultiComparableT(i,multiComparable(f,false)) {}
}

这篇关于规范关系运算符(==,&lt;,...)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆