Can you create custom operators in C ++?

Is it possible to create a custom operator so that you can do such things?

if ("Hello, world!" contains "Hello") ... 

Note: this is a separate question: "This is a good idea ...";)

+38
c ++ operators c-preprocessor templates metaprogramming
04 Oct '09 at 2:04
source share
6 answers

Yes! (well, kind of)

There are several publicly available tools to help you. Both use preprocessor code generation to create patterns that implement user-defined operators. These statements consist of one or more built-in statements combined with an identifier.

Since these are not ordinary user statements, but just operator overload tricks, there are a few caveats:

  • Macros are evil. If you make a mistake, the compiler will be almost useless to track the problem.
  • Even if you get the macro correctly, if there is an error in your use of the operator or in the definition of your operation, the compiler will be a little more useful.
  • You must use a valid identifier as part of the statement. If you need a more character operator, you can use _ , o or similarly simple alphanumeric characters.

CustomOperators

While I was working on my own library for this purpose (see below), I came across this project. The following is an example of creating an avg statement:

 #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) 

Idop

What started with the exercise in sheer frivolity was my own solution to this problem. Here's a similar example:

 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_> 

Key Differences

  • CustomOperators supports postfix unary operators
  • IdOp templates use links, not pointers, to exclude the use of free storage and enable a complete estimate of the time taken to complete an operation
  • IdOp makes it easy to specify multiple operations for the same root identifier
+31
04 Oct '09 at 2:07
source share

In "Syntactic Aspartame" by Sander Stokes, a method is considered in detail, which allows using the following format:

 if ("Hello, world!" <contains> "Hello") ... 

Essentially, you need a proxy object with overloaded operators "<" and ">". A proxy does all the work; "contains" may just be a singleton without its own behavior or data.

 // 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; } 
+11
May 09 '15 at 10:40 pm
source share

To be more precise, C ++ itself only supports the creation of new overloads of existing operations, and not the creation of new operators. There are languages ​​(for example, ML and most of its descendants) that allow you to create completely new operators, but C ++ is not one of them.

From the looks of things (at least), the CustomOperators library mentioned in another answer also does not support fully customizable operators. At least if I read things correctly, it (internally) translates your user statement into overloading the existing statement. This simplifies the work due to some flexibility - for example, when you create a new operator in ML, you can give it a priority different from the function of any built-in operator.

+2
04 Oct '09 at 2:52
source share

Your suggestion would be nothing more than syntactic sugar for:

 if( contains( "Hello, world!", "Hello" ) ... 

and in fact there are already functions to execute in both cstring and std :: string. Perhaps this is a bit like the answer: "Is that a good idea?" but not quite; rather asking: "why do you need this?"

0
Oct 04 '09 at 7:46
source share

Technically, no. That is, you cannot extend the set of operator+ , operator- , etc. But what you propose in your example is something else. You are wondering if there is a definition of β€œcontains” such that string-literal "contains" string-literal is an expression with non-trivial logic ( #define contains "" is a trivial case).

There are not many expressions that can take the form string-literal X string-literal . This is because the string literals themselves are expressions. So, you are looking for a language rule of the form expr X expr . There are a lot of them, but for operators all the rules, and they do not work on lines. Despite the obvious implementation, "Hello, " + "world" not a valid expression. So what else could be X in string-literal X string-literal ? It cannot be the expression itself. It cannot be a type name, typedef name, or template name. It cannot be a function name. In fact, it can only be a macro, which is the only remaining named objects. For this, see the answer "Yes (well, kind)."

0
Oct 05 '09 at 9:18
source share

I created the following two macros:

 #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) 

Then you just need to define your custom operator, as in the following example:

 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 

After you have configured your statement, you can use it as a predefined statement:

 bool a = true myOr false; // a == true 
0
Jun 21 '19 at 14:46
source share



All Articles