我正在致力于在 C++ 中实现类似 Rust 的特征。每个特征都需要大量样板代码,因此我需要以某种方式生成 C++ 代码。 如果不可能的话,我想使用具有给定语法或其他语法的
trait
宏。
另外,我想知道是否可以使用 clang 或现有库的插件?
#define trait(name, ...) ???
trait(Shape,
(auto area() const -> f32),
(void dump(std::ostream& stream) const)
);
namespace stl {
template <typename>
struct trait;
template <typename Trait>
using dyn = trait<Trait>::dyn;
template <typename Self, typename Trait>
concept impl = trait<Trait>::template impl<Self>;
}
struct Shape;
template <>
struct stl::trait<Shape> {
struct interface {
auto (*area)(void*) -> f32;
auto (*dump)(void*, std::ostream& stream) -> void;
};
template<typename Self>
static constexpr auto impl = requires {
static_cast<auto(Self::*)() const -> f32>(&Self::area);
static_cast<auto(Self::*)(std::ostream& stream) const -> void>(&Self::dump);
};
template<typename Self> requires impl<Self>
static constexpr auto interface_for = interface{
.area = [](void* self_ptr) -> f32 {
return static_cast<Self*>(self_ptr)->area();
},
.dump = [](void* self_ptr, std::ostream& stream) -> void {
return static_cast<Self*>(self_ptr)->dump(stream);
}
};
struct dyn {
interface const* vtable = {};
void* object = {};
template<typename Self>
constexpr dyn(Self& self) noexcept
: vtable(std::addressof(interface_for<Self>))
, object(std::addressof(self)) {}
dyn(dyn&) = delete;
dyn(dyn&&) = delete;
auto operator=(dyn&) -> dyn& = delete;
auto operator=(dyn&&) -> dyn& = delete;
auto area() const -> f32 {
return vtable->area(object);
}
auto dump(std::ostream& stream) const -> void {
return vtable->dump(object, stream);
}
};
};
使用示例
struct Circle {
f32 radius = {};
auto area() const -> f32 {
return 2.0F * f32(M_PI) * radius;
}
void dump(std::ostream& stream) const {
stream << fmt::format("Circle{{ radius: {} }}", radius) << std::endl;
}
};
void test_impl(stl::impl<Shape> auto const& shape) {
auto area = shape.area();
shape.dump(std::cout);
}
void test_dyn(stl::dyn<Shape> const& shape) {
auto area = shape.area();
shape.dump(std::cout);
}
auto c = Circle(2.0F);
test_dyn(c);
test_dyn(stl::dyn<Shape>(c));
test_impl(c);
test_impl(stl::dyn<Shape>(c));