#ifndef INCLUDED_BOBCAT_BINOPS_
#define INCLUDED_BOBCAT_BINOPS_

// This header file requires the separate inclusion of <bobcat/typetrait>
//
//
// The templates in this file were not defined in the namespace FBB to enhance
// their usability. If you want to declare them in a namespace of your own
// include them in your namespace-block, like this:
//  namespace YOUR_NAMESPACE
//  {
//      #include <bobcat/binops>
//  }

template <typename Class>
inline Class operator*(Class &&lhs, Class const &rhs)
{
    return lhs *= rhs;
}

template <typename Class>
inline Class operator/(Class &&lhs, Class const &rhs)
{
    return lhs /= rhs;
}

template <typename Class>
inline Class operator%(Class &&lhs, Class const &rhs)
{
    return lhs %= rhs;
}

template <typename Class>
inline Class operator+(Class &&lhs, Class const &rhs)
{
    return lhs += rhs;
}

template <typename Class>
inline Class operator-(Class &&lhs, Class const &rhs)
{
    return lhs -= rhs;
}

template <typename Class>
inline Class operator^(Class &&lhs, Class const &rhs)
{
    return lhs ^= rhs;
}

template <typename Class>
inline Class operator&(Class &&lhs, Class const &rhs)
{
    return lhs &= rhs;
}

template <typename Class>
inline Class operator|(Class &&lhs, Class const &rhs)
{
    return lhs |= rhs;
}

template <typename Class>
inline Class operator<<(Class &&lhs, Class const &rhs)
{
    return lhs <<= rhs;
}

template <typename Class>
inline Class operator>>(Class &&lhs, Class const &rhs)
{
    return lhs >>= rhs;
}

template <typename LHS, typename RHS>
inline typename FBB::IfElse<FBB::LpromotesR<LHS, RHS>::yes, LHS, RHS>::type 
       operator*(LHS const &lhs, RHS const &rhs)
{
    typedef typename FBB::IfElse<
                                FBB::LpromotesR< LHS, RHS >::yes, LHS, RHS
                            >::type type;
    type tmp(lhs);
    return std::move(tmp) * type(rhs);
}

template <typename LHS, typename RHS>
inline typename FBB::IfElse<FBB::LpromotesR<LHS, RHS>::yes, LHS, RHS>::type 
       operator/(LHS const &lhs, RHS const &rhs)
{
    typedef typename FBB::IfElse<
                                FBB::LpromotesR< LHS, RHS >::yes, LHS, RHS
                            >::type type;
    type tmp(lhs);
    return std::move(tmp) / type(rhs);
}

template <typename LHS, typename RHS>
inline typename FBB::IfElse<FBB::LpromotesR<LHS, RHS>::yes, LHS, RHS>::type 
       operator%(LHS const &lhs, RHS const &rhs)
{
    typedef typename FBB::IfElse<
                                FBB::LpromotesR< LHS, RHS >::yes, LHS, RHS
                            >::type type;
    type tmp(lhs);
    return std::move(tmp) % type(rhs);
}

template <typename LHS, typename RHS>
inline typename FBB::IfElse<FBB::LpromotesR<LHS, RHS>::yes, LHS, RHS>::type 
       operator+(LHS const &lhs, RHS const &rhs)
{
    typedef typename FBB::IfElse<
                                FBB::LpromotesR< LHS, RHS >::yes, LHS, RHS
                            >::type type;
    type tmp(lhs);
    return std::move(tmp) + type(rhs);
}

template <typename LHS, typename RHS>
inline typename FBB::IfElse<FBB::LpromotesR<LHS, RHS>::yes, LHS, RHS>::type 
       operator-(LHS const &lhs, RHS const &rhs)
{
    typedef typename FBB::IfElse<
                                FBB::LpromotesR< LHS, RHS >::yes, LHS, RHS
                            >::type type;
    type tmp(lhs);
    return std::move(tmp) - type(rhs);
}

template <typename LHS, typename RHS>
inline typename FBB::IfElse<FBB::LpromotesR<LHS, RHS>::yes, LHS, RHS>::type 
       operator&(LHS const &lhs, RHS const &rhs)
{
    typedef typename FBB::IfElse<
                                FBB::LpromotesR< LHS, RHS >::yes, LHS, RHS
                            >::type type;
    type tmp(lhs);
    return std::move(tmp) & type(rhs);
}

template <typename LHS, typename RHS>
inline typename FBB::IfElse<FBB::LpromotesR<LHS, RHS>::yes, LHS, RHS>::type 
       operator^(LHS const &lhs, RHS const &rhs)
{
    typedef typename FBB::IfElse<
                                FBB::LpromotesR< LHS, RHS >::yes, LHS, RHS
                            >::type type;
    type tmp(lhs);
    return std::move(tmp) ^ type(rhs);
}

template <typename LHS, typename RHS>
inline typename FBB::IfElse<FBB::LpromotesR<LHS, RHS>::yes, LHS, RHS>::type 
       operator|(LHS const &lhs, RHS const &rhs)
{
    typedef typename FBB::IfElse<
                                FBB::LpromotesR< LHS, RHS >::yes, LHS, RHS
                            >::type type;
    type tmp(lhs);
    return std::move(tmp) | type(rhs);
}

template <typename LHS, typename RHS>
inline typename FBB::IfElse<FBB::LpromotesR<LHS, RHS>::yes, LHS, RHS>::type 
       operator>>(LHS const &lhs, RHS const &rhs)
{
    typedef typename FBB::IfElse<
                                FBB::LpromotesR< LHS, RHS >::yes, LHS, RHS
                            >::type type;
    type tmp(lhs);
    return std::move(tmp) >> type(rhs);
}


template <typename LHS, typename RHS>
inline typename FBB::IfElse<FBB::LpromotesR<LHS, RHS>::yes, LHS, RHS>::type 
       operator<<(LHS const &lhs, RHS const &rhs)
{
    typedef typename FBB::IfElse<
                                FBB::LpromotesR< LHS, RHS >::yes, LHS, RHS
                            >::type type;
    type tmp(lhs);
    return std::move(tmp) << type(rhs);
}

#endif


