There are additional (bad) ways of handling this. One of my favorite bad methods goes like:
class Vector { public: Vector(float x = 0.0f, float y = 0.0f, float z = 0.0f) : x_(x), y_(y), z_(z) {} public: float x_; float y_; float z_;};template <typename Op>struct LtProxy { LtProxy(const Vector & r) : ref_(r) {} const Vector & ref_;};const struct DotT {} dot;LtProxy<DotT> operator<(const Vector & lhs, const DotT & rhs) { return LtProxy<DotT>(lhs);}float operator>(const LtProxy<DotT> & lhs, const Vector & rhs) { return ( (lhs.ref_.x_ * rhs.x_) + (lhs.ref_.y_ * rhs.y_) + (lhs.ref_.z_ * rhs.z_) );}const struct CrossT {} cross;LtProxy<CrossT> operator<(const Vector & lhs, const CrossT & rhs) { return LtProxy<CrossT>(lhs);}Vector operator>(const LtProxy<CrossT> & lhs, const Vector & rhs) { return Vector( (lhs.ref_.y_ * rhs.z_ - lhs.ref_.z_ * rhs.y_), (lhs.ref_.z_ * rhs.x_ - lhs.ref_.x_ * rhs.z_), (lhs.ref_.x_ * rhs.y_ - lhs.ref_.y_ * rhs.x_) );}int main(int, char **) { Vector a(0, 1, 3); Vector b(4, 2, 1); float dot_product = a <dot> b; std::cout << dot_product << std::endl; Vector cross_product = a <cross> b; std::cout << cross_product.x_ << std::endl; std::cout << cross_product.y_ << std::endl; std::cout << cross_product.z_ << std::endl; return 0;}
This abuses the associativity of relational operators and operator overloading in general, is unmaintainable and can give operator precdence headaches, but it''s fun.
Of course, I have a slightly twisted definition of fun.