Concept
Constraining a template to only accept certain types avoids a lot of obscure compilation errors; concepts are the C++20 tool that makes this clean.
Overview
RE:MAKE 2D defines its own concepts to restrict its templates to the expected types: shapes, textures, physics bodies,
actors, signals, savable types, and base value types. This lives in the header "remake2d/concept.hpp", relying on std::derived_from
and std::same_as/std::is_arithmetic_v.
Inheritance concepts
Most concepts here simply check that a type derives from a given base class:
template<typename G>
concept IsShape = std::derived_from<G, class Geometry>;
template<typename T>
concept IsTexture = std::derived_from<T, class TextureBase>;
template<typename P>
concept IsPhysic = std::derived_from<P, class PhysicBody>;
template<typename A>
concept IsActor = std::derived_from<A, class ActorBase>;
template<typename S>
concept IsSignal = std::derived_from<S, class SignalBase>;
template<typename S>
concept IsSavable = std::derived_from<S, class ISavable>;
IsShape: constrains a type to inherit fromGeometry.IsTexture: constrains a type to inherit fromTextureBase.IsPhysic: constrains a type to inherit fromPhysicBody.IsActor: constrains a type to inherit fromActorBase.IsSignal: constrains a type to inherit fromSignalBase.IsSavable: constrains a type to implementISavable.
These show up throughout the engine whenever a function or class needs to stay generic while still rejecting arbitrary types:
// collision test between two shapes
template<IsShape T1, IsShape T2> bool intersect(T1 a, T2 b) {
return a.hasIntersected(b);
}
IsBasicType
IsBasicType gathers every base value type of the engine, plus any arithmetic type (int, float, etc.):
template<typename T>
concept IsBasicType = std::same_as<T, struct Vec2d> ||
std::same_as<T, struct Fact2d> ||
std::same_as<T, struct Grid2d> ||
std::same_as<T, struct Dim2d> ||
std::same_as<T, struct Area> ||
std::same_as<T, struct Triangulation> ||
std::same_as<T, struct Color> ||
std::same_as<T, struct HSL> ||
std::is_arithmetic_v<T>;
This concept is what lets any base value stream directly into a Text with <<, without overloading the operator for each type one by one:
Info
IsBasicType accepts any arithmetic type. This means custom numeric aliases such as rmk::i32 or rmk::f32 also satisfy the concept.