How do you define a new operator?

I was going through the documents on how to define something, but it appears that it only takes arguments in the form of a function call. e.g.

#define func(a,b) a-b // just an example.

But I was hoping to find a way to define a logical Xor function to use when needed. I wanted to give it a ^^ format. e.g.

#define a^^b ((a||b)&&!(a&&b)) // unfortunately doesn't work.

So how can I do something like that? We can overload operators, is it possible to create new ones?
XOR currently exists. Here is an example of it being used.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

using namespace std;

bool A, B;

int main() {
     A = true;
     B = true;
     cout << A ^ B << endl; //A XOR B = False.

     A = true;
     B = false;
     cout << A ^ B << endl; //A XOR B = true.

     return 0;
}


Hope that helps.
not quite. that conversation came up already, in another thread in the articles section.

The Xor you are reffering to is a bitwise Xor. While it would work correctly with bools, it will not neccesarily work correctly with return values.

1
2
if (2 ^ 2) // this would return false
if (2 ^ 3) // this would return true 


So I was thinking of trying to create a logical Xor, not a bitwise Xor.

even making a function for it would be difficult. I was about to try to do that, but then realized that the number of different types of arguments would mean I would have to do it as a template. And I havn't had much experience making templates before.

Edit: actually just found typeid() function. wondering if it can be used inside a parameter list?
Last edited on
You cannot create new operators in C++. If you want to use the XOR logically, you must first cast to bool:
if ((bool)foo ^ (bool)bar)

Sorry...
ok.. i had thought of that, but am uncertain how some data types will convert..

i am sure int will convert fine, zero being false, and any other number being true.

but am unsure how a float will convert, especially if a very low number, such as 0.00001

i'm unsure what an equivilent to false would be for a char.. empty '' ? that should be the same as null. i guess same rule applies for string?

But then.. i suppose when you use logical operators such as (2 && 'y') it is implicitatly casting to bools already. so explicitly casting to bool should yeild same results.
Last edited on
For converting to bool, the "non-zero is one" rule applies.
'\0' is the false character.
How would you xor two strings?

EDIT: Oh, by the way, ((bool)a ^ (bool)b) == (!a && b || a && !b)
Last edited on
How would you xor two strings?


In a logical sense, it would be false if empty and true otherwise.
empty = null = false
At least that's how I would interpret it.

hrm. ( ( ! a && b ) || ( a && ! b ) ) that works too.. I wonder how that would compare to ( ( a || b ) && ! ( a && b ) ) in effeciency.
Oh, look at that. I didn't think that formula was correct. Mine is the classic xor formula (well, at least the one I was taught in electronics). It's probably pointless to measure their performance. I look at them and all I see is a difference of one not in favor of yours, but an optimizer compiler might mangle them beyond recognition. It's always faster to just ^, as that translates to a single instruction. And xor is so rarely needed as a logical operator it's probably not worth worrying about any of this.
Just write a function called xor, passes 2 args, and do the rest.
I never heard of yours before.. never even occured to me. I came up with mine a long time ago, because I was working with some scripted langauge that didn't have any xor.. bitshift or otherwise. So I thought, how is xor defined, and came up with or and not and which converts over to mine directly.

So, whenever working with a langauge that doesn't have a logical xor, that's how I've always done it. at least c++ has the benifit of type casting.

@QWERTYman
I was thinking of doing that too, but the number of different types of arguments that can possibly be passed to such a function is too many to just overload the function over and over.

I was looking at typeid() and wondering if it could be used in a function parameter list. or maybe even a define (which would prevent double execution of any ++a or function calls)

1
2
3
4
// not tested

// the reason for declaring new variables is any operators or function calls are done only once
#define LXOR(a,b) ( { typeid(a) i = (a); typeid(b) j = (b); ((i || j)&&!(i && j)) }) 


or something similar once i figgure out all of the syntax to doing something like that.
Last edited on
You can make a template function instead of overloading the same function over and over... Let the compiler do it for you :D
1
2
3
4
template<class T>
inline bool XOR(T a, T b){
   return ( ( ! a && b ) || ( a && ! b ) ) ;
}


The "( ( ! a && b ) || ( a && ! b ) )" comes out if you use the Karnaugh map for the XOR gate.
The one Aakanaar uses is a little more complicated but if you apply the boolean laws to simplify it, it comes to the one helios mentioned...

[EDIT] I tried it with string type and I have the following error:
binary '&&' : 'std::string' does not define this operator or a conversion to a type acceptable to the predefined operator


The string class doesn't have an overloaded operator&& ...
But now that I'm thinking of it, why would you need a && operator with a string?
Last edited on
There is such a thing as overkill. If you are only interested in boolean values, then explicitly convert to boolean before using XOR. Otherwise you'd have to explicitly define what it means to convert an object to boolean.

For example, as helios posited: what would be the value of
string1 ^^ string2
? Strings are not booleans, so you would have to define the operation to mean something. If you want a boolean result defined on the non-emptiness of a string, then be explicit about that:
!string1.empty() ^^ !string2.empty()

The same is true for
string1 && string2
What does that mean?
!string1.empty() && !string2.empty()
means something, because it is explicit about how a boolean value is extracted from a string.

While it would be nice to have a logical xor function, remember that the only real difference between the logical and bitwise functions are whether or not the operands are first converted to boolean. That is:
a && b is the same as (bool)a & (bool)b is the same as (a != 0) & (b != 0) which is how it is actually implemented.

The same is true for ||.

There is no ^^, but since && and || are really syntactic sugar for bitwise operations on bool-converted operands, it is just as understandable to use them without the sugar:
1
2
3
(bool)a & (bool)b
(bool)a | (bool)b
(bool)a ^ (bool)b

Note again that (bool) is only applicable to integer argument types (and those that define an operator bool() const member function).

int, char, and bool are the only integer types defined by C++. (enums and pointers are type-promoted to int.)

float and double are not integer types.

struct, class, and union are not integer types.

Arrays are not integer types.

Those are all the types there are.

Alas.
Oh, but you forgot about short circuit evaluation. That's another difference between bitwise and logical operators.
Last edited on
Good point!
ok.. I know now that ((bool) a ^ (bool) b) is the better way to go..

I can probably even do a define as such
#define LXOR(a,b) ((bool)(a) ^ (bool)(b))

that way I don't have to worry about remembering to cast it in the code.
But I did get to thinking about the to forumla's we had before
( ( ! a && b ) || ( a && ! b ) )
( ( a || b ) && ! ( a && b ) )

and did some calculations on the number of evaluations each one would require, once you figgure in short circuiting.. and came up with the following.

a = 0, b = 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
( ( ! a && b ) || ( a && ! b ) )

( ( ! 0 && 0 ) || ( 0 && ! 0 ) )
( ( ! false && 0 ) || ( 0 && ! 0 ) )
( ( true && 0 ) || ( 0 && ! 0 ) )
( ( true && false ) || ( 0 && ! 0 ) )
( false || ( 0 && ! 0 ) )
( false || ( false && ! 0 ) )
( false || false )
( false ) // 7 steps

( ( a || b ) && ! ( a && b ) )

( ( 0 || 0 ) && ! ( 0 && 0 ) )
( ( false || 0 ) && ! ( 0 && 0 ) )
( ( false || false ) && ! ( 0 && 0 ) )
( false && ! ( 0 && 0 ) )
( false ) // 4 steps 


a = 1, b = 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
( ( ! a && b ) || ( a && ! b ) )

( ( ! 1 && 0 ) || ( 1 && ! 0 ) )
( ( ! true && 0 ) || ( 1 && ! 0 ) )
( ( false && 0 ) || ( 1 && ! 0 ) )
( false || ( 1 && ! 0 ) )
( false || ( true  && ! 0 ) )
( false || ( true && ! false ) )
( false || ( true && true ) )
( false || true )
( true ) // 8 steps

( ( a || b ) && ! ( a && b ) )

( ( 1 || 0 ) && ! ( 1 && 0 ) )
( ( true || 0 ) && ! ( 1 && 0 ) )
( true && ! ( 1 && 0 ) )
( true && ! ( true && 0 ) )
( true && ! ( true && false ) )
( true && ! false )
( true && true )
( true ) // 7 steps 


a = 0, b = 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
( ( ! a && b ) || ( a && ! b ) )

( ( ! 0 && 1 ) || ( 0 && ! 1 ) )
( ( ! false && 1 ) || ( 0 && ! 1 ) )
( ( true && 1 ) || ( 0 && ! 1 ) )
( ( true && true ) || ( 0 && ! 1 ) )
( true || ( 0 && ! 1 ) )
( true || ( false && ! 1 ) )
( true || false )
( true ) // 7 steps

( ( a || b ) && ! ( a && b ) )

( ( 0 || 1 ) && ! ( 0 && 1 ) )
( ( false || 1 ) && ! ( 0 && 1 ) )
( ( false || true ) && ! ( 0 && 1 ) )
( true && ! ( 0 && 1 ) )
( true && ! ( false && 1 ) )
( true && ! false )
( true && true )
( true ) // 7 steps 


a = 1, b = 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
( ( ! a && b ) || ( a && ! b ) )

( ( ! 1 && 1 ) || ( 1 && ! 1 ) )
( ( ! true && 1 ) || ( 1 && ! 1 ) )
( ( false && 1 ) || ( 1 && ! 1 ) )
( false || ( 1 && ! 1 ) )
( false || ( true && ! 1 ) )
( false || ( true && ! true ) )
( false || ( true && false ) )
( false || false )
( false ) // 8 steps

( ( a || b ) && ! ( a && b ) )

( ( 1 || 1 ) && ! ( 1 && 1 ) )
( ( true || 1 ) && ! ( 1 && 1 ) )
( true && ! ( 1 && 1 ) )
( true && ! ( true && 1 ) )
( true && ! ( true && true ) )
( true && ! true )
( true && false )
( false ) // 7 steps 


Almost identical.. with one exception. My way may be more complicated, but it actually saves evaluations due to short circuiting
I think, it´s all about logical XOR, the not exixting operator XOR would have two operands, both should be bool or a implicit convertable object. So thats the only types such an operator have to be work on, isn´t it?
That's exactly the problem. There isn't a logical XOR in C++. And you can't create new operators to fill the gap.
...unless you were to change the inner working of your IDE, and thus "break" C++ itself.

Don't try it.
Some people implement special preprocessors. You could use the m4 preprocessor. Or you could write your own...

For example, Qt makes slots and signals and other object stuff work with just about any compiler by preprocessing the files with a custom application.

But it does require some magical ability.
Topic archived. No new replies allowed.