Can We Write x ** y in C++ Like We Do in Python?

Najam Ul Hassan
5 min readApr 25, 2023

--

The shortest and the simplest answer would be, YES!

The second question would be HOW?

Understand the statement

The statement that we are trying to evaluate looks something like,

x ** y;

What should be the types?

One thing is certain; we have to overload some operators. To overload an operator in C++, it must accept at least one user-defined object as an argument. That being said, either x or y has to be an object of a class/struct.

I will show you later, but for now, trust me, it’ll be better if that object is the second argument which, in this case, is y. The type for x can be any primitive type but I prefer double.

What should that class look like?

The class will internally store a double (or any other primitive type but double is a better option). Let’s see that class.

class Exponent {
public:
Exponent(double y) : y{y} {}

private:
double y;
};

Using this definition, we can now create an object of the Exponent class and treat it like a double. Let’s now create an object of this class.

How to use this class?

This is how we can create an object of this class in the main( ) (or anywhere else for that matter).

class Exponent {
public:
Exponent(double y) : y{y} {}

private:
double y;
};

int main() {
double x{2.};
Exponent y{4.};

auto result{x ** y}; // Won't work yet (of course)

}

Let’s break it down

If you look closely 🧐, you can easily understand what we need to do here. I’ll show you how…

The third line in the main( ) function, where we are calling the operator, look closer! We can also write it as,

auto result{x * *y};

Because C++ is not indent/space-sensitive, this code is exactly the same as above. It should already be crystal clear to you by now what we have to do to make this work.

Getting things ready

This first thing we have to do is to overload the indirection operator of the Exponent class. But what would it do 🤔? Well, we only want to make the compiler happy that our class does have an operator of that sort. We only need to send the object to actual operator (that we’ll see in a bit). Let’s see the code. It’ll make better sense 😁.

class Exponent {
public:
Exponent(double y) : y{y} {}

Exponent& operator*() {
return *this;
}

private:
double y;
};

This definition of the operator will return the same object that we call the operator on without doing anything to it. You can also define a const version of the operator like,

const Exponent& operator*() const {
return *this;
}

Now, let’s see how we can implement an operator that takes a double and an Exponent and calls the std::pow on them.

// Prototype of the operator
double operator*(double x, Exponent y);

// This should also be made friend of the
// Exponent class because we need to
// access its member 'y'.
class Exponent {
public:
Exponent(double y) : y{y} {}

Exponent& operator*() {
return *this;
}

private:
// doesn't have to be private though
friend double operator*(double x, Exponent y);
double y;
};

Implementation of the operator

Let us now see the entire code with complete implementation.

#include <iostream>
#include <cmath>

class Exponent {
public:
Exponent(double y) : y{y} {}

Exponent& operator*() { return *this; }
const Exponent& operator*() const { return *this; }

private:
friend double operator*(double x, Exponent y);
double y;
};

double operator*(double x, Exponent y) {
return std::pow(x, y.y);
}

int main() {
double x{2.};
Exponent y{4.};

auto result{x ** y};

std::cout << "result = " << result << std::endl;

}

This is all you need for this. It’ll output the expected result.

What if we rearrange the variables?

What if we want to write the code in such a way that the Exponent (user-defined) object is the first argument and the double variable is the second?

auto result{y ** x}; // What about this one??

For this to work, you will have a number of ways. The easiest would be to use a (double) pointer.

int main() {
double number{2.};
auto x{&number}; // double*
Exponent y{4.};

auto result{y ** x};
}

Now, because the first argument is a user-defined object, we can overload the member operator of our class. Let’s see how…

class Exponent {
public:
Exponent(double y) : y{y} {}

double operator*(double y) { return std::pow(this->y, y); }

private:
friend double operator*(double x, Exponent y);
double y;
};

Don’t get confused by the names of the variables! The x is treated as a y in the operator, that’s why I’ve called it y there. Feel free to rename it to whatever makes sense to you.

Compiling that code now would give us the expected output. Let’s see all of the code in one place.

#include <iostream>
#include <cmath>

// be better if we renamed it to Base now 😅
class Exponent {
public:
Exponent(double y) : y{y} {}

double operator*(double y) { return std::pow(this->y, y); }

private:
friend double operator*(double x, Exponent y);
double y;
};

int main() {
double number{2.};
auto x{&number};
Exponent y{4.};

auto result{y ** x};

std::cout << "result = " << result << std::endl;
}

More ways of doing the same thing

I would not suggest doing this 🥴 but with the modern C++ features (C++11 and above), we can do something really cool.

int main() {
double x{2.};
Exponent y{4.};

auto result{y ** ((double*)&x)};

std::cout << "result = " << result << std::endl;
}

This is taking the address of that variable and casting it to a double pointer only to later dereference it. This will work the same.

But where are the modern features, you might ask…

Well, there’s another…

int main() {
double x{2.};
Exponent y{4.};

auto result{y ** (&(double&)std::move(2.))};

std::cout << "result = " << result << std::endl;
}

This would also give you the same result.

Conclusion

You may have noticed, I used reference at some places and copy at the others. You could use reference at all places (for this particular case) because the Exponent class is only storing a double internally which is 8 bytes. A reference is just an address which, on a 64-bit architecture, also happens to be 8 bytes (hence the 64-bits 😉). It wouldn’t make much of a difference anyway. Although, you’re welcome to interchange references and copies if you like.

I teach programming on YouTube as well 🙃. If you like the way I explain stuff, check out my channel as well. You might even like that more 😄.

CodeMite (Hindi)

eN. Programming (English)

Instagram

And if you understand Hindi, I also made a video on this topic, check it out here.

--

--

Najam Ul Hassan
Najam Ul Hassan

Written by Najam Ul Hassan

0 Followers

I love learning and teaching programming.

No responses yet