エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

自作の演算子その2

#include <iostream>

// 例:三次元ベクトルクラス
class Vec3
{
public:
    explicit Vec3(double x = 0, double y = 0, double z = 0) : x_(x), y_(y), z_(z) {}

    double x() const { return x_; }
    double y() const { return y_; }
    double z() const { return z_; }

    Vec3& operator += (const Vec3& vec3) { x_ += vec3.x_; y_ += vec3.y_; z_ += vec3.z_; return *this; }
    Vec3& operator -= (const Vec3& vec3) { x_ -= vec3.x_; y_ -= vec3.y_; z_ -= vec3.z_; return *this; }
    Vec3& operator *= (double s)         { x_ *= s; y_ *= s; z_ *= s; return *this; }
    Vec3& operator /= (double s)         { x_ /= s; y_ /= s; z_ /= s; return *this; }
    double dot(const Vec3& vec3) const   { return (x_ * vec3.x_) + (y_ * vec3.y_) + (z_ * vec3.z_); }
    Vec3 cross(const Vec3& vec3) const   { return Vec3((y_ * vec3.z_) - (z_ * vec3.y_), (z_ * vec3.x_) - (x_ * vec3.z_), (x_ * vec3.y_) - (y_ * vec3.x_)); }

private:
    double x_;
    double y_;
    double z_;
};

// 加算、減算、乗算(スカラ)、除算(スカラ)
Vec3 operator + (Vec3 lhs, const Vec3& rhs) { return (lhs += rhs); }
Vec3 operator - (Vec3 lhs, const Vec3& rhs) { return (lhs -= rhs); }
Vec3 operator * (Vec3 lhs, double rhs)      { return (lhs *= rhs); }
Vec3 operator / (Vec3 lhs, double rhs)      { return (lhs /= rhs); }

// 挿入演算子
std::ostream& operator << (std::ostream& out, const Vec3& vec3)
{
    return out << "(" << vec3.x() << ", " << vec3.y() << ", " << vec3.z() << ")";
}

// ここから本題

// 任意の演算子を作るための構造体テンプレートと関数テンプレート

template<typename T>
struct Operator
{
    explicit Operator(const Vec3& vec3) : vec3(vec3) {}
    const Vec3& vec3;
};

template<typename T>
inline Operator<T> operator % (const Vec3& vec3, T)
{
    return Operator<T>(vec3);
}


// 内積と外積の演算子を定義してみる

// 演算子に使う型と文字
enum DOT   { dot   }; // 内積
enum CROSS { cross }; // 外積

// 演算子 dot を使った時に実行される演算
inline double operator % (const Operator<DOT>& op, const Vec3& vec3)
{
    return op.vec3.dot(vec3);
}

// 演算子 cross を使った時に実行される演算
inline Vec3 operator % (const Operator<CROSS>& op, const Vec3& vec3)
{
    return op.vec3.cross(vec3);
}

int main(int, char* [])
{
    Vec3 v1(1, 2, 3);
    Vec3 v2(4, 5, 6);

    std::cout << "v1          = " << v1              << "\n";
    std::cout << "v2          = " << v2              << "\n";
    std::cout << "v1 + v2     = " << (v1 + v2)       << "\n";
    std::cout << "v1 - v2     = " << (v1 - v2)       << "\n";
    std::cout << "v1 *  2     = " << (v1 * 2)        << "\n";
    std::cout << "v2 /  2     = " << (v2 / 2)        << "\n";
    std::cout << "v1 dot v2   = " << (v1 %dot% v2)   << "\n";
    std::cout << "v1 cross v2 = " << (v1 %cross% v2) << "\n";

    return 0;
}