Ist es möglich, einen benutzerdefinierten Operator zu erstellen, mit dem man solche Dinge tun kann?
if ("Hello, world!" contains "Hello") ...
Hinweis: Dies ist eine andere Frage als "Ist es eine gute Idee,..." ;)
Ist es möglich, einen benutzerdefinierten Operator zu erstellen, mit dem man solche Dinge tun kann?
if ("Hello, world!" contains "Hello") ...
Hinweis: Dies ist eine andere Frage als "Ist es eine gute Idee,..." ;)
Es gibt einige öffentlich zugängliche Tools, die Ihnen dabei helfen können. Beide verwenden die Präprozessor-Code-Generierung, um Vorlagen zu erstellen, die die benutzerdefinierten Operatoren implementieren. Diese Operatoren bestehen aus einem oder mehreren eingebauten Operatoren in Verbindung mit einem Bezeichner.
Da es sich hierbei nicht um benutzerdefinierte Operatoren, sondern lediglich um Tricks der Operatorüberladung handelt, gibt es einige Vorbehalte:
_
, o
oder ähnlich einfache alphanumerische Zeichen.Während ich an meiner eigenen Bibliothek für diesen Zweck arbeitete (siehe unten), stieß ich auf dieses Projekt. Hier ist ein Beispiel für die Erstellung einer avg
Betreiber:
#define avg BinaryOperatorDefinition(_op_avg, /)
DeclareBinaryOperator(_op_avg)
DeclareOperatorLeftType(_op_avg, /, double);
inline double _op_avg(double l, double r)
{
return (l + r) / 2;
}
BindBinaryOperator(double, _op_avg, /, double, double)
Was begann als eine Übung in reiner Frivolität wurde meine eigene Sicht auf dieses Problem. Hier ist ein ähnliches Beispiel:
template<typename T> class AvgOp {
public:
T operator()(const T& left, const T& right)
{
return (left + right) / 2;
}
};
IDOP_CREATE_LEFT_HANDED(<, _avg_, >, AvgOp)
#define avg <_avg_>
Es gibt eine Methode, die ausführlich in Syntaktisches Aspartam". von Sander Stoks, die Ihnen die Verwendung des folgenden Formats ermöglichen würde:
if ("Hello, world!" <contains> "Hello") ...
Im Wesentlichen benötigen Sie ein Proxy-Objekt, das mit den Operatoren '<' und '>' überladen ist. Der Proxy übernimmt die gesamte Arbeit; "contains" kann einfach ein Singleton ohne eigenes Verhalten oder eigene Daten sein.
// Not my code!
const struct contains_ {} contains;
template <typename T>
struct ContainsProxy
{
ContainsProxy(const T& t): t_(t) {}
const T& t_;
};
template <typename T>
ContainsProxy<T> operator<(const T& lhs, const contains_& rhs)
{
return ContainsProxy<T>(lhs);
}
bool operator>(const ContainsProxy<Rect>& lhs, const Rect& rhs)
{
return lhs.t_.left <= rhs.left &&
lhs.t_.top <= rhs.top &&
lhs.t_.right >= rhs.right &&
lhs.t_.bottom >= rhs.bottom;
}
Ich habe die folgenden zwei Makros erstellt:
#define define const struct
#define operator(ReturnType, OperatorName, FirstOperandType, SecondOperandType) OperatorName ## _ {} OperatorName; template <typename T> struct OperatorName ## Proxy{public:OperatorName ## Proxy(const T& t) : t_(t){}const T& t_;static ReturnType _ ## OperatorName ## _(const FirstOperandType a, const SecondOperandType b);};template <typename T> OperatorName ## Proxy<T> operator<(const T& lhs, const OperatorName ## _& rhs){return OperatorName ## Proxy<T>(lhs);}ReturnType operator>(const OperatorName ## Proxy<FirstOperandType>& lhs, const SecondOperandType& rhs){return OperatorName ## Proxy<FirstOperandType>::_ ## OperatorName ## _(lhs.t_, rhs);}template <typename T> inline ReturnType OperatorName ## Proxy<T>::_ ## OperatorName ## _(const FirstOperandType a, const SecondOperandType b)
Dann müssen Sie nur noch Ihren eigenen Operator wie im folgenden Beispiel definieren:
define operator(bool, myOr, bool, bool) { // Arguments are the return type, the name of the operator, the left operand type and the right operand type, respectively
return a || b;
}
#define myOr <myOr> // Finally, you have to define a macro to avoid to put the < and > operator at the start and end of the operator name
Wenn Sie Ihren Operator einmal eingerichtet haben, können Sie ihn als vordefinierten Operator verwenden:
bool a = true myOr false;
// a == true
Dies war zwar eine interessante Übung, aber sie zeigt nur, wie schlecht es ist, einen makrofähigen Precompiler zu haben. Das Hinzufügen von benutzerdefinierten Operatoren wie diesem kann leicht zu einer Art Metasprache führen. Obwohl wir wissen, wie schlecht C++ konzipiert ist (vor allem wenn man bedenkt, dass es ursprünglich als eine Reihe von Erweiterungen für C konzipiert wurde), sollten wir es nicht ändern. Wenn man nicht den Standard C++ verwenden kann, was die einzige Möglichkeit ist, den Code für andere Leute verständlich zu halten, sollte man einfach zu einer anderen Sprache wechseln, die das, was man tun möchte, so macht, wie man es möchte. Es gibt Tausende von Sprachen - kein Grund, an C++ herumzupfuschen, um es anders zu machen.
KURZ: Sie sollten diesen Code einfach nicht verwenden. Sie sollten von der Verwendung von Makros absehen, es sei denn, sie werden auf die gleiche Weise wie Inline-Methoden verwendet.
Um etwas genauer zu sein: C++ selbst unterstützt nur die Erstellung neuer Überladungen bestehender Operationen, NICHT aber die Erstellung neuer Operatoren. Es gibt Sprachen (z.B. ML und die meisten seiner Nachfahren), die es erlauben, völlig neue Operatoren zu erstellen, aber C++ gehört nicht dazu.
So wie es aussieht, unterstützt (zumindest) die in der anderen Antwort erwähnte CustomOperators-Bibliothek auch keine vollständig benutzerdefinierten Operatoren. Zumindest, wenn ich die Dinge richtig lese, ist es (intern) übersetzen Ihre benutzerdefinierte Operator in eine Überladung eines vorhandenen Operators. Das macht die Dinge einfacher, auf Kosten einer gewissen Flexibilität - zum Beispiel, wenn Sie einen neuen Operator in ML erstellen, können Sie ihm einen Vorrang geben, der sich von dem eines eingebauten Operators unterscheidet.
Technisch gesehen, nein. Das heißt, Sie können die Menge der operator+
, operator-
und so weiter. Aber was Sie in Ihrem Beispiel vorschlagen, ist etwas anderes. Sie fragen sich, ob es eine Definition von "enthält" gibt, die string-literal "contains" string-literal
ist ein Ausdruck mit nicht-trivialer Logik ( #define contains ""
ist der triviale Fall).
Es gibt nicht viele Ausdrücke, die die folgende Form haben können string-literal X string-literal
. Das liegt daran, dass Stringliterale selbst Ausdrücke sind. Sie suchen also nach einer Sprachregel der Form expr X expr
. Es gibt eine ganze Reihe davon, aber das sind alles Regeln für Operatoren, und die funktionieren nicht bei Strings. Trotz der offensichtlichen Implementierung, "Hello, " + "world"
ist kein gültiger Ausdruck. Was kann X also sonst noch sein in string-literal X string-literal
? Es kann kein Ausdruck selbst sein. Es kann kein Typename, ein Typedef-Name oder ein Template-Name sein. Es kann kein Funktionsname sein. Es kann wirklich nur ein Makro sein, das die einzigen verbleibenden benannten Entitäten sind. Siehe dazu die Antwort "Ja (na ja, sozusagen)".
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.