-
Notifications
You must be signed in to change notification settings - Fork 614
Closed
Labels
Description
To generate the C++ object hierarchy there are a few things to figure out.
One of them is .hpp vs .cpp files. This is probably quite easy.
Sum types
How do we express sum types in C++?
Consider a simple example (in Rust):
pub enum Rotation3D {
Quaternion(Quaternion),
AxisAngle(RotationAxisAngle),
}Inheritance
Using inheritance for sum-types adds a lot of allocation and indirections, which will be quite costly.
std::variant
std::variant was introduced in C++17, and tries to be like a Rust union. Some downsides:
- Minimum supported version of C++17
- It uses the the type-id of the thing it holds, i.e. cannot distinguish between float degrees and float radians unless degrees and radians are their own new-types
*std::variantis also overall very unergonomic, so we would still want to generate wrappers around it - It reportedly compiles quite slowly (so much template magic)
Tagged unions
- Implemented in C++ codegen of structs and unions #2707
For Plain Old Data (POD) a tagged union is very efficient:
enum Rotation3DKind {
Quaternion,
AxisAngle,
};
union Rotation3DData {
Quaternion quaternion;
AxisAngle axis_angle;
};
struct Rotation3D {
kind: Rotation3DKind,
data: Rotation3DData,
// implicit conversions:
Rotation3D(Quaternion);
Rotation3D(AxisAngle);
};However, this becomes quite error prone if the contained data is not plain-old-data, but has allocations.
It is still doable if we make the union and all the fields private. We would need to take care to overload (or make private):
- The copy constructor
- The move constructor
- Copy assignment
- Move assignment
- Destructor
In other words, it would have to be something like:
namespace { // private
enum Rotation3DKind {
Quaternion,
AxisAngle,
};
union Rotation3DData {
Quaternion quaternion;
AxisAngle axis_angle;
};
} // namespace
namespace rr {
class Rotation3D {
private:
_kind: Rotation3DKind,
_data: Rotation3DData,
public:
// Implicit constructors (maybe should be explicit?):
Rotation3D(Quaternion&& quaternion) {
_kind = Rotation3DKind::Quaterion;
_data.quaternion = quaternion;
}
Rotation3D(AxisAngle&& axis_angle);
Rotation3D(const Rotation3D& axis_angle); // TODO: copy-constructor
Rotation3D(Rotation3D&& axis_angle) noexecpt; // TODO: move-constructor
~Rotation3D {
switch self.kind {
Rotation3DKind::Quaterion:
self.data.quaterion.~Quaterion();
break;
Rotation3DKind::AxisAngle:
self.data.axis_angle.~AxisAngle();
break;
}
}
Rotation3D& operator=(const Rotation3D& axis_angle); // TODO: copy-assignment
Rotation3D& operator=(Rotation3D&& axis_angle) noexecpt; // TODO: move-assigment
}
}