Erased is your constexpr friendly type erasure wrapper type. It is a C++ type-erasure implementation developed with performance and ease of use in mind.
It is heavily inspired by AnyAny.
The tested compilers are:
- MSVC (19.32 and above):
constexpr
does not work since MSVC does not yet handlevirtual
functions in a constexpr context. - Clang (19.1 and above)
- GCC (14.1 and above)
Here are the currently supported features
constexpr
friendly- Small Object Optimization
- Copy and
noexcept
move operations - Extendible with multiple behaviors
- Macros helper to remove more and more boilerplate.
- Natural syntax at call site.
Here is an example of use:
struct Draw {
constexpr static void invoker(const auto &self, std::ostream &stream) {
return self.draw(stream);
}
// not necessary, but makes the client code easier to write
constexpr void draw(this const auto &erased, std::ostream &stream) {
return erased.invoke(Draw{}, stream);
}
};
using Drawable = erased::erased<Draw>;
void render(const Drawable &x) {
x.draw(std::cout);
}
struct Circle {
void draw(std::ostream &stream) const {
stream << "Circle\n";
}
};
struct Rectangle {
void draw(std::ostream &stream) const {
stream << "Rectangle\n";
}
};
int main() {
Circle c;
Rectangle r;
render(c);
render(r);
}
Here is the same with macros
ERASED_MAKE_BEHAVIOR(Draw, draw,
(const &self, std::ostream &stream) requires(self.draw(), stream)->void);
using Drawable = erased::erased<Draw>;
The erased::erased
type has only a constructor and destructor by default. We provide these behaviors to extend easily the given type:
- Copy: Add copy constructor and copy assignment operator
- Move: Add noexcept move constructor and noexcept move assignment operator
For example, if you want to have a copyable and movable Drawable, you can do
// Draw behavior
using Drawable = erased::erased<Draw, erased::Move, erased::Copy>;
Here is the list of people who help me to develop and test this library: