Skip to content

Latest commit

 

History

History
635 lines (490 loc) · 16.3 KB

operators.md

File metadata and controls

635 lines (490 loc) · 16.3 KB

演算子を自動定義する

C++は演算子のオーバーロードによって、ユーザー定義型に演算子を持たせることができる。各演算子には関連性があり、ひとつ定義すれば他の演算子も同じように書ける。たとえば、operator<()さえ定義すれば、operator>()operator<=(), operator>=()operator<()から定義できる。Boost Operators Libraryは、このような関連演算子を自動的に定義する機構を提供する。

インデックス

整数型をラップした型を作るためには、多くの演算子を定義する必要がある。

Boost.Operatorsによって関連演算子を自動定義することによって、これだけで整数型を定義することができる。

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::operators<MyInt> {
    int v;
public:
    MyInt(int v) : v(v) {}

    bool operator<(const MyInt& x) const { return v < x.v; }
    bool operator==(const MyInt& x) const { return v == x.v; }
    MyInt& operator+=(const MyInt& x) { v += x.v; return *this; }
    MyInt& operator-=(const MyInt& x) { v -= x.v; return *this; }
    MyInt& operator*=(const MyInt& x) { v *= x.v; return *this; }
    MyInt& operator/=(const MyInt& x) { v /= x.v; return *this; }
    MyInt& operator%=(const MyInt& x) { v %= x.v; return *this; }
    MyInt& operator|=(const MyInt& x) { v |= x.v; return *this; }
    MyInt& operator&=(const MyInt& x) { v &= x.v; return *this; }
    MyInt& operator^=(const MyInt& x) { v ^= x.v; return *this; }
    MyInt& operator++() { ++v; return *this; }
    MyInt& operator--() { --v; return *this; }
};

int main()
{
    // operator<()によって自動生成される演算子
    {
        const MyInt x = 3;
        assert(x <  MyInt(4));
        assert(x >  MyInt(2));
        assert(x <= MyInt(3));
        assert(x >= MyInt(3));
    }
    // operator==()によって自動生成される演算子
    {
        const MyInt x = 3;
        assert(x == MyInt(3));
        assert(x != MyInt(2));
    }
    // operator+=()によって自動生成される演算子
    {
        MyInt x = 3;
        x += MyInt(2);
        assert(x == MyInt(5));

        const MyInt y = x + MyInt(4);
        assert(y == MyInt(9));
    }
    // 以下略...
}

boost::operators型をprivate継承したクラスでは、

  • operator<()を定義することによって、operator>()operator<=()operator>=()が自動的に定義され、
  • operator==()を定義することによって、operator!=()が定義され、
  • operator+=によってoperator+()が定義され、他の関連演算子も同様に自動的に定義される。

大小比較の演算子、すなわち、operator<()operator>()operator<=()operator>=()は、boost::less_than_comparableprivate継承することにより、operator<()だけを定義すれば、それ以外の関連演算子が自動的に定義される。

メンバ関数として定義する場合

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::less_than_comparable<MyInt> {
    int v;
public:
    MyInt(int v) : v(v) {}

    bool operator<(const MyInt& x) const { return v < x.v; }
};

int main()
{
    // operator<()によって自動生成される演算子
    {
        const MyInt x = 3;
        assert(x <  MyInt(4));
        assert(x >  MyInt(2));
        assert(x <= MyInt(3));
        assert(x >= MyInt(3));
    }
}

非メンバ関数として定義する場合

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::less_than_comparable<MyInt, MyInt> {
    int v;
public:
    MyInt(int v) : v(v) {}

    friend bool operator<(const MyInt& a, const MyInt& b)
        { return a.v < b.v; }
};

int main()
{
    // operator<()によって自動生成される演算子
    {
        const MyInt x = 3;
        assert(x <  MyInt(4));
        assert(x >  MyInt(2));
        assert(x <= MyInt(3));
        assert(x >= MyInt(3));
    }
}

等値比較の演算子、すなわち、operator==()operator!=()は、boost::equality_comparableprivate継承することにより、operator==()だけを定義すれば、関連するoperator!=()が自動的に定義される。

メンバ関数として定義する場合

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::equality_comparable<MyInt> {
    int v;
public:
    MyInt(int v) : v(v) {}

    bool operator==(const MyInt& x) const
        { return v == x.v; }
};

int main()
{
    // operator==()によって自動生成される演算子
    {
        const MyInt x = 3;
        assert(x == MyInt(3));
        assert(x != MyInt(2));
    }
}

非メンバ関数として定義する場合

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::equality_comparable<MyInt, MyInt> {
    int v;
public:
    MyInt(int v) : v(v) {}

    friend bool operator==(const MyInt& a, const MyInt& b)
        { return a.v == b.v; }
};

int main()
{
    // operator==()によって自動生成される演算子
    {
        const MyInt x = 3;
        assert(x == MyInt(3));
        assert(x != MyInt(2));
    }
}

加算演算子であるoperator+=()operator+()は、boost::addableprivate継承することにより、operator+=()を定義するだけでoperator+()が自動的に定義される。

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::addable<MyInt> {
public:
    int v;

    MyInt(int v) : v(v) {}

    MyInt& operator+=(const MyInt& x)
    {
        v += x.v;
        return *this;
    }
};

int main()
{
    // operator+=()によって自動生成される演算子
    MyInt x = 3;
    x += MyInt(2);
    assert(x.v == 5);

    const MyInt y = x + MyInt(4);
    assert(y.v == 9);
}

減算演算子であるoperator-=()operator-()は、boost::subtractableprivate継承することにより、operator-=()を定義するだけでoperator-()が自動的に定義される。

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::subtractable<MyInt> {
public:
    int v;

    MyInt(int v) : v(v) {}

    MyInt& operator-=(const MyInt& x)
    {
        v -= x.v;
        return *this;
    }
};

int main()
{
    // operator-=()によって自動生成される演算子
    MyInt x = 5;
    x -= MyInt(2);
    assert(x.v == 3);

    const MyInt y = x - MyInt(1);
    assert(y.v == 2);
}

乗算演算子であるoperator*=(), operator*()は、boost::multipliableprivate継承することにより、operator*=()定義するだけで、自動的にoperator*()が定義される。

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::multipliable<MyInt> {
public:
    int v;

    MyInt(int v) : v(v) {}

    MyInt& operator*=(const MyInt& x)
    {
        v *= x.v;
        return *this;
    }
};

int main()
{
    // operator*=()によって自動生成される演算子
    MyInt x = 5;
    x *= MyInt(2);
    assert(x.v == 10);

    const MyInt y = x * MyInt(2);
    assert(y.v == 20);
}

除算演算子であるoperator/=()operator/()は、boost::dividableprivate継承することにより、operator/=()を定義するだけで、operator/()が自動定義される。

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::dividable<MyInt> {
public:
    int v;

    MyInt(int v) : v(v) {}

    MyInt& operator/=(const MyInt& x)
    {
        v /= x.v;
        return *this;
    }
};

int main()
{
    // operator/=()によって自動生成される演算子
    MyInt x = 20;
    x /= MyInt(2);
    assert(x.v == 10);

    const MyInt y = x / MyInt(2);
    assert(y.v == 5);
}

剰余演算子であるoperator%=()operator%()は、boost::modableprivate継承することにより、operator%=()を定義するだけで、operator%()が自動定義される。

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::modable<MyInt> {
public:
    int v;

    MyInt(int v) : v(v) {}

    MyInt& operator%=(const MyInt& x)
    {
        v %= x.v;
        return *this;
    }
};

int main()
{
    // operator%=()によって自動生成される演算子
    MyInt x = 20;
    x %= MyInt(2);
    assert(x.v == 0);

    const MyInt y = MyInt(7) % MyInt(2);
    assert(y.v == 1);
}

OR演算子であるoperator|=()operator|()は、boost::orableprivate継承することにより、operator|=()を定義するだけで、operator|()が自動定義される。

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::orable<MyInt> {
public:
    int v;

    MyInt(int v) : v(v) {}

    MyInt& operator|=(const MyInt& x)
    {
        v |= x.v;
        return *this;
    }
};

int main()
{
    // operator|=()によって自動生成される演算子
    MyInt x = 0x55;
    x |= MyInt(0x0F);
    assert(x.v == 0x5F);

    const MyInt y = MyInt(0x55) | MyInt(0x0F);
    assert(y.v == 0x5F);
}

AND演算子、operator&=()operator&()は、boost::andableprivate継承することにより、operator&=()を定義するだけで、operator&()が自動定義される。

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::andable<MyInt> {
public:
    int v;

    MyInt(int v) : v(v) {}

    MyInt& operator&=(const MyInt& x)
    {
        v &= x.v;
        return *this;
    }
};

int main()
{
    // operator&=()によって自動生成される演算子
    MyInt x = 0x55;
    x &= MyInt(0x0F);
    assert(x.v == 0x05);

    const MyInt y = MyInt(0x55) & MyInt(0x0F);
    assert(y.v == 0x05);
}

XOR演算子であるoperator^=()operator^()は、boost::xorableprivate継承することにより、operator^=()を定義するだけで、operator^()が自動定義される。

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::xorable<MyInt> {
public:
    int v;

    MyInt(int v) : v(v) {}

    MyInt& operator^=(const MyInt& x)
    {
        v ^= x.v;
        return *this;
    }
};

int main()
{
    // operator^=()によって自動生成される演算子
    MyInt x = 0x55;
    x ^= MyInt(0x0F);
    assert(x.v == 0x5A);

    const MyInt y = MyInt(0x55) ^ MyInt(0x0F);
    assert(y.v == 0x5A);
}

インクリメント演算子である前置++(), 後置++()は、boost::incrementableprivate継承することにより、前置++()を定義するだけで、後置++()が自動定義される。

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::incrementable<MyInt> {
public:
    int v;

    MyInt(int v) : v(v) {}

    MyInt& operator++()
    {
        ++v;
        return *this;
    }
};

int main()
{
    // operator++()によって自動生成される演算子
    MyInt x = 1;
    assert((++x).v == 2);

    MyInt y = 1;
    assert((y++).v == 1);
    assert(y.v == 2);
}

デクリメント演算子である前置--()、後置--()は、boost::decrementableprivate継承することにより、前置--()を定義するだけで、後置--()が自動定義される。

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::decrementable<MyInt> {
public:
    int v;

    MyInt(int v) : v(v) {}

    MyInt& operator--()
    {
        --v;
        return *this;
    }
};

int main()
{
    // operator--()によって自動生成される演算子
    MyInt x = 2;
    assert((--x).v == 1);

    MyInt y = 2;
    assert((y--).v == 2);
    assert(y.v == 1);
}

左シフト演算子であるoperator<<=()operator<<()は、boost::left_shiftableprivate継承することにより、operator<<=()を定義するだけで、operator<<()が自動定義される。

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::left_shiftable<MyInt> {
public:
    int v;

    MyInt(int v) : v(v) {}

    MyInt& operator<<=(MyInt x)
    {
        v <<= x.v;
        return *this;
    }
};

int main()
{
    // operator<<=()によって自動生成される演算子
    MyInt x = 100;
    x <<= MyInt(1);
    assert(x.v == 200);

    MyInt y = 100;
    y = y << MyInt(1);
    assert(y.v == 200);
}

右シフト演算子であるoperator>>=()operator>>()は、boost::right_shiftableprivate継承することにより、operator>>=()を定義するだけで、operator>>()が自動定義される。

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::right_shiftable<MyInt> {
public:
    int v;

    MyInt(int v) : v(v) {}

    MyInt& operator>>=(MyInt x)
    {
        v >>= x.v;
        return *this;
    }
};

int main()
{
    // operator>>=()によって自動生成される演算子
    MyInt x = 100;
    x >>= MyInt(1);
    assert(x.v == 50);

    MyInt y = 100;
    y = y >> MyInt(1);
    assert(y.v == 50);
}

等値比較演算子であるoperator==()は、小なり演算子operator<()で定義することができる。

boost::equivalentprivate継承することにより、operator<()を定義するだけで、operator==()が自動定義される。

#include <cassert>
#include <boost/operators.hpp>

class MyInt : private boost::equivalent<MyInt> {
public:
    int v;

    MyInt(int v) : v(v) {}

    bool operator<(MyInt x) const
    {
        return v < x.v;
    }
};

int main()
{
    // operator<()によって自動生成される演算子
    assert(MyInt(1) <  MyInt(2));
    assert(MyInt(2) == MyInt(2));
}