C++0x 標準ライブラリ完全解説 〜 No.01 namespace rel_ops,

該当規格: 20.3.1 Operators [operators], N3225
http://sites.google.com/site/cpprefjp/reference/utility/rel_ops


さて、それでは早速、具体的なライブラリに移っていこうと思います。
とはいえ、初回から飛ばすのもアレなので、まずは軽いものを、
というわけで、 の rel_ops を紹介したいと思います。


これは比較演算子の多重定義を助けるためのヘルパ関数群で、
で唯一、 C++98/03 から全く変化していないライブラリです。

定義

namespace std {
  namespace rel_ops {
  
    template <class T>
    bool operator!=( const T& x, const T& y ) {
      return !( x == y );
    }
    
    template <class T>
    bool operator> ( const T& x, const T& y ) {
      return y < x;
    }
    template <class T>
    bool operator<=( const T& x, const T& y ) {
      return !( y < x );
    }
    template <class T>
    bool operator>=( const T& x, const T& y ) {
      return !( x < y );
    }
    
  }
}

解説

== 演算子から != 演算子を、 < 演算子から > 演算子と <= 演算子と >= 演算子を、それぞれ定義します。
どのように定義されるかは、上のコードを参照してください。


実際の使い方としては、

#include <utility>

namespace ns
{
  class hoge
  {
    /* 〜 */
  };
  
  inline bool operator==( hoge const& x, hoge const& y ) {
    return 〜;
  }
  inline bool operator!=( hoge const& x, hoge const& y ) {
    return std::rel_ops::operator!=( x, y );
  }
  
  inline bool operator<( hoge const& x, hoge const& y ) {
    return 〜;
  }
  inline bool operator>( hoge const& x, hoge const& y ) {
    return std::rel_ops::operator>( x, y );
  }
  inline bool operator<=( hoge const& x, hoge const& y ) {
    return std::rel_ops::operator<=( x, y );
  }
  inline bool operator>=( hoge const& x, hoge const& y ) {
    return std::rel_ops::operator>=( x, y );
  }

}

このように使います。


毎回同じようなコードを書くのが面倒な場合には、プリプロセッサを使って

#include <utility>

namespace ns
{
  class hoge
  {
    /* 〜 */
  };
  
  inline bool operator==( hoge const& x, hoge const& y ) {
    return 〜;
  }
  inline bool operator<( hoge const& x, hoge const& y ) {
    return 〜;
  }
  
  #define GENERATE_REL_OPS( klass, op )                         \
    inline bool operator op( klass const& x, klass const& y ) { \
      return std::rel_ops::operator op( x, y );                 \
    }
  /* GENERATE_REL_OPS( klass, op ) */
  
  GENERATE_REL_OPS( hoge, != )
  GENERATE_REL_OPS( hoge, >  )
  GENERATE_REL_OPS( hoge, <= )
  GENERATE_REL_OPS( hoge, >= )
  
}

と自動生成させてみると、いい感じなんじゃないでしょうか。


と、ここまで書くと、便利なヘルパ関数群のように思えるかもしれませんが、
実のところ std::rel_ops は、実際のコーディングには まず現れることはありません。


というのも、その用途には、 Boost.Operators という、より扱いやすいライブラリがある為で、

そちらを使って:

#include <boost/operators.hpp>

namespace ns {
  class hoge
    : private boost::totally_ordered<hoge>
  {
    /* 〜 */
  };
  
  inline bool operator==( hoge const& x, hoge const& y ) {
    return 〜;
  }
  inline bool operator<( hoge const& x, hoge const& y ) {
    return 〜;
  }

}

と書いた方が、ずっと気軽に、ずっと安全に、比較演算子を定義できるからです。


実際、 std::rel_ops よりも Boost.Operators を使う方が 遥かに利点は多く、

  • std::rel_ops では、中身は自動生成してくれても、定義自身は手ないしプリプロセッサ等を使って明示的に書かなければいけないが、 Boost.Operators は何も書かなくても自動生成される*1
  • std::rel_ops では同じ型同士の比較しか扱えないが、 Boost.Operators では異なる型の間での比較も行える
  • std::rel_ops では比較演算子しか扱っていないが、 Boost.Operators では operator+operator* 等、比較演算子以外も扱える
  • std::rel_ops の順序比較は完全順序集合であることを暗に要求しているが、 Boost.Operators はそれ以外の順序も扱える

等、 std::rel_ops の強みは「標準であること」以外には実質的に存在せず、

仮に何らかの理由で Boost が使えないとしても、
Boost.Operators に相当するクラスを自前で用意したほうが 何かと便利なため、
std::rel_ops は正直に言って、全く覚える必要のないライブラリと言えます。


個人的には、 C++0x では Boost.Operators を標準入りさせ、
std::rel_ops は deprecated 扱いにしたほうがよかった、とすら思う程です。

とはいえ、今からそうするのは IS 制定の時期を無意味に遅らせるだけでしょうから、
C++0x の次の規格に期待、といったところでしょうか。

*1:どうやって実装しているかは、 Barton-Nackman trick で検索すると分かります