Example
[[maybe_unused]] constexpr [:substitute(^std::tuple, {^int, ^float}):] tuple{}; // std::tuple<int, float>Puzzle
- Can you implement
soa_vectorwith reflection?
template <class T>
class soa_vector; // TODO
int main() {
struct vec3_t {
float x, y, z;
};
soa_vector<vec3_t> v{};
v.push_back({.x = 1, .y = 2, .z = 3});
assert(1 == v[0].x and 2 == v[0].y and 3 == v[0].z);
}Solutions
template<class T>
class soa_vector {
public:
constexpr void push_back(const T value) {
v.push_back(value~member_values)...;
}
[[nodiscard]] constexpr auto operator[](const auto pos) const {
return T{v[pos]...};
}
private:
std::vector<T~member_types> ...v;
};
int main() {
struct vec3_t { float x, y, z; };
soa_vector<vec3_t> v{};
v.push_back({.x=1, .y=2, .z=3});
assert(1 == v[0].x and 2 == v[0].y and 3 == v[0].z);
}template <class T>
class soa_vector {
public:
constexpr void push_back(const T value) {
[&, this]<auto... Ns>(std::index_sequence<Ns...>) { (std::get<Ns>(v).push_back(value.[:std::meta::nonstatic_data_members_of(^T)[Ns]:]), ...); }(members);
}
[[nodiscard]] constexpr auto operator[](const auto pos) const {
return [&, this]<auto... Ns>(std::index_sequence<Ns...>) { return T{std::get<Ns>(v)[pos]...}; }(members);
}
private:
template<class... Ts> using vector = std::vector<Ts...>;
[[nodiscard]] static consteval auto tuple_of_vectors(const auto type) {
std::vector<std::meta::info> members{};
for (auto member : nonstatic_data_members_of(type)) {
members.push_back(substitute(^vector, {type_of(member)})); // with std::vector -> std::vector<float, allocator<_Tp>>
}
return substitute(^std::tuple, members); // define_class can also be used instead
}
static constexpr auto members = std::make_index_sequence<std::size(std::meta::nonstatic_data_members_of(^T))>{};
[:tuple_of_vectors(^T):] v;
};
int main() {
struct vec3_t {
float x, y, z;
};
soa_vector<vec3_t> v{};
v.push_back({.x = 1, .y = 2, .z = 3});
assert(1 == v[0].x and 2 == v[0].y and 3 == v[0].z);
}namespace impl {
template <typename... Ts>
using vector = std::vector<Ts...>;
template <class T>
struct soa_base_t;
consteval auto make_soa_t(std::meta::info type) -> std::meta::info {
auto members = std::meta::nonstatic_data_members_of(type);
std::vector<std::meta::nsdm_description> new_members;
for (const auto& member : members) {
auto new_type = std::meta::substitute(^vector, {
std::meta::type_of(member)});
auto new_member =
std::meta::nsdm_description(new_type, {.name = std::meta::name_of(member)});
new_members.push_back(new_member);
}
return std::meta::define_class(std::meta::substitute(^soa_base_t,
{
type}),
new_members);
}
template <class T>
using soa_t = [:make_soa_t(^T):];
} // namespace impl
template <class T>
class soa_vector : impl::soa_t<T> {
constexpr static auto C = std::meta::nonstatic_data_members_of(^T).size();
public:
void push_back(const T& value) {
[&value, this]<auto... Is>(std::index_sequence<Is...>) {
(this->[:std::meta::nonstatic_data_members_of(^impl::soa_t<T>)[Is]:]
.push_back(value.[:std::meta::nonstatic_data_members_of(^T)[Is]:]), ...);
}(std::make_index_sequence<C>());
}
[[nodiscard]] constexpr auto operator[](std::size_t index) const -> T {
return [&index, this]<auto... Is>(std::index_sequence<Is...>) {
return T{
this->[:std::meta::nonstatic_data_members_of(^impl::soa_t<T>)[Is]:].at(index)...};
}(std::make_index_sequence<C>());
}
};