Boaz Brickner
ee42b2db93
C++ interop: Support more binary operators ( #6017 )
...
Already supported: `+`.
Newly supported: `-`, `*`, `/`, `%`, `&`, `|`, `^`, `<<`, `>>`, `==`,
`!=`, `<`, `>`, `<=`, `>=`.
Partially supported due to lack of reference support: `+=`, `-=`, `*=`,
`/=`, `%=`, `&=`, `|=`, `^=`.
Not supported due to lack of reference support: `<<=`, `>>=`.
Not supported (I think Carbon doesn't want overloading these): `&&`,
`||`.
C++ Interop Demo:
```c++
// my_number.h
class MyNumber {
public:
explicit MyNumber(int value) : value_(value) {}
auto value() const -> int { return value_; }
void set_value(int value) { value_ = value; }
private:
int value_;
};
// Arithmetic
auto operator+(MyNumber lhs, MyNumber rhs) -> MyNumber;
auto operator-(MyNumber lhs, MyNumber rhs) -> MyNumber;
auto operator*(MyNumber lhs, MyNumber rhs) -> MyNumber;
auto operator/(MyNumber lhs, MyNumber rhs) -> MyNumber;
auto operator%(MyNumber lhs, MyNumber rhs) -> MyNumber;
// Bitwise
auto operator&(MyNumber lhs, MyNumber rhs) -> MyNumber;
auto operator|(MyNumber lhs, MyNumber rhs) -> MyNumber;
auto operator^(MyNumber lhs, MyNumber rhs) -> MyNumber;
auto operator<<(MyNumber lhs, int shift) -> MyNumber;
auto operator>>(MyNumber lhs, int shift) -> MyNumber;
// Compound Arithmetic
auto operator+=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull;
auto operator-=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull;
auto operator*=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull;
auto operator/=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull;
auto operator%=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull;
// Compound Bitwise
auto operator&=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull;
auto operator|=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull;
auto operator^=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull;
// Relational
auto operator==(MyNumber lhs, MyNumber rhs) -> bool;
auto operator!=(MyNumber lhs, MyNumber rhs) -> bool;
auto operator<(MyNumber lhs, MyNumber rhs) -> bool;
auto operator>(MyNumber lhs, MyNumber rhs) -> bool;
auto operator<=(MyNumber lhs, MyNumber rhs) -> bool;
auto operator>=(MyNumber lhs, MyNumber rhs) -> bool;
```
```c++
// my_number.cpp
#include "my_number.h"
// Arithmetic
auto operator+(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() + rhs.value());
}
auto operator-(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() - rhs.value());
}
auto operator*(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() * rhs.value());
}
auto operator/(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() / rhs.value());
}
auto operator%(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() % rhs.value());
}
// Bitwise
auto operator&(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() & rhs.value());
}
auto operator|(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() | rhs.value());
}
auto operator^(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() ^ rhs.value());
}
auto operator<<(MyNumber lhs, int shift) -> MyNumber {
return MyNumber(lhs.value() << shift);
}
auto operator>>(MyNumber lhs, int shift) -> MyNumber {
return MyNumber(lhs.value() >> shift);
}
// Compound Arithmetic
auto operator+=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull {
return &(*lhs = *lhs + rhs);
}
auto operator-=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull {
return &(*lhs = *lhs - rhs);
}
auto operator*=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull {
return &(*lhs = *lhs * rhs);
}
auto operator/=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull {
return &(*lhs = *lhs / rhs);
}
auto operator%=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull {
return &(*lhs = *lhs % rhs);
}
// Compound Bitwise
auto operator&=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull {
return &(*lhs = *lhs & rhs);
}
auto operator|=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull {
return &(*lhs = *lhs | rhs);
}
auto operator^=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull {
return &(*lhs = *lhs ^ rhs);
}
// Relational
auto operator==(MyNumber lhs, MyNumber rhs) -> bool {
return lhs.value() == rhs.value();
}
auto operator!=(MyNumber lhs, MyNumber rhs) -> bool {
return lhs.value() != rhs.value();
}
auto operator<(MyNumber lhs, MyNumber rhs) -> bool {
return lhs.value() < rhs.value();
}
auto operator>(MyNumber lhs, MyNumber rhs) -> bool {
return lhs.value() > rhs.value();
}
auto operator<=(MyNumber lhs, MyNumber rhs) -> bool {
return lhs.value() <= rhs.value();
}
auto operator>=(MyNumber lhs, MyNumber rhs) -> bool {
return lhs.value() >= rhs.value();
}
```
```carbon
// main.carbon
library "Main";
import Core library "io";
import Cpp library "my_number.h";
fn PrintBool(b: bool) {
if (b) {
Core.Print(1);
} else {
Core.Print(0);
}
}
fn Run() -> i32 {
// Arithmetic
var num1: Cpp.MyNumber = Cpp.MyNumber.MyNumber(14);
var num2: Cpp.MyNumber = Cpp.MyNumber.MyNumber(5);
Core.Print(num1.value());
Core.Print(num2.value());
Core.Print((num1 + num2).value());
Core.Print((num1 - num2).value());
Core.Print((num1 * num2).value());
Core.Print((num1 / num2).value());
Core.Print((num1 % num2).value());
// Bitwise
var bits1: Cpp.MyNumber = Cpp.MyNumber.MyNumber(12);
var bits2: Cpp.MyNumber = Cpp.MyNumber.MyNumber(10);
Core.Print(bits1.value());
Core.Print(bits2.value());
Core.Print((bits1 & bits2).value());
Core.Print((bits1 | bits2).value());
Core.Print((bits1 ^ bits2).value());
Core.Print((bits1 << 2).value());
Core.Print((bits1 >> 1).value());
// Compound Arithmetic
var c: Cpp.MyNumber = Cpp.MyNumber.MyNumber(100);
Core.Print(c.value());
&c += Cpp.MyNumber.MyNumber(10);
Core.Print(c.value());
&c -= Cpp.MyNumber.MyNumber(20);
Core.Print(c.value());
&c *= Cpp.MyNumber.MyNumber(2);
Core.Print(c.value());
&c /= Cpp.MyNumber.MyNumber(6);
Core.Print(c.value());
&c %= Cpp.MyNumber.MyNumber(9);
Core.Print(c.value());
// Compound Bitwise
&c |= Cpp.MyNumber.MyNumber(12);
Core.Print(c.value());
&c &= Cpp.MyNumber.MyNumber(7);
Core.Print(c.value());
&c ^= Cpp.MyNumber.MyNumber(10);
Core.Print(c.value());
// Relational
var rel1: Cpp.MyNumber = Cpp.MyNumber.MyNumber(20);
var rel2: Cpp.MyNumber = Cpp.MyNumber.MyNumber(30);
var rel3: Cpp.MyNumber = Cpp.MyNumber.MyNumber(20);
Core.Print(rel1.value());
Core.Print(rel2.value());
Core.Print(rel3.value());
PrintBool(rel1 == rel3);
PrintBool(rel1 != rel2);
PrintBool(rel1 < rel2);
PrintBool(rel2 > rel1);
PrintBool(rel1 <= rel3);
PrintBool(rel1 >= rel2);
return 0;
}
```
```shell
$ clang -c my_number.cpp
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link my_number.o main.o --output=demo
$ ./demo
14
5
19
9
70
2
4
12
10
8
14
6
48
6
100
110
90
180
30
3
15
7
13
20
30
20
1
1
1
1
1
0
```
Part of https://github.com/carbon-language/carbon-lang/issues/5995 .
2025-09-05 13:03:10 +00:00