En C++, il existe une liste d'opérateurs prédéfinis, dont la plupart sont surchargeables (.* ne l'est pas). De plus, tout Le nom peut être utilisé comme un opérateur comme :
#include <iostream>
// generic LHSlt holder
template<typename LHS, typename OP>
struct LHSlt {
LHS lhs_;
};
// declare myop as an operator-like construct
enum { myop };
// parse 'lhs <myop' into LHSlt
template<typename LHS>
LHSlt<LHS, decltype(myop)> operator<(const LHS& lhs, decltype(myop))
{
return { lhs };
}
// declare (int <myop> int) -> int
int operator>(LHSlt<int, decltype(myop)> lhsof, int rhs)
{
int& lhs = lhsof.lhs_;
// here comes your actual implementation
return (lhs + rhs) * (lhs - rhs);
}
// strictly optional
#define MYOP <myop>
int main() {
std::cout << (5 <myop> 2) << ' ' << (5 MYOP 2);
}
Clause de non-responsabilité : Ceci, à proprement parler, se traduit par (5 < myop) > 2
qui est LHSlt<int, decltype(myop)>(5) > 2
. Il ne s'agit donc pas d'un nouvel "opérateur", au sens du C++, mais il est utilisé exactement de la même manière, même en termes d'ADL. De plus, si le type est grand, vous voudrez probablement stocker const T&
.
Notez que vous pouvez faire cela avec n'importe quel opérateur binaire qui peut être défini en dehors de la classe ; la précédence est basée sur la précédence des deux côtés ( <
y >
). Ainsi, vous pouvez avoir par exemple *myop*
, +myop+
, <<myop>>
, <myop>
, |myop|
dans cet ordre de préséance.
Si vous voulez une associativité droite, cela devient un peu plus délicat. Vous aurez besoin à la fois d'un support RHS et d'un support LHS (ce dernier étant LHSlt
ici) et utiliser les opérateurs environnants de manière à ce que celui de droite ait une plus grande priorité que celui de gauche, par ex. a |myop> b |myop>c
est a |myop> (b |myop> c)
. Ensuite, vous avez besoin de la fonction pour votre type et votre type de support en tant que lhs.