template
class Archetype;
template
struct ComponentStorage {
T* data = nullptr;
Deep_Inline T* Get() const;
};
template
class Archetype : private ComponentStorage... {
// ...
}
< /code>
Я хочу позволить ему принимать компоненты, которые не имеют тривиальных конструкторов, но это означает, что при создании сущности мне нужно иметь возможность передавать аргументы каждому требуемому конструктору компонентов.archetype.CreateEntity(std::in_place_type, arg1, arg2, std::in_place_type, arg3, arg4);
So component A is constructed being passed arg1, arg2 and B is constructed with arg3, arg4 etc...
Ideally order doesn't matter as it uses the tags std::in_place_type
I have a working system to extract the needed arguments using std :: tuple :
#include
#include
#include
#include
// Helpers to detect if a type is std::in_place_type
template
struct is_in_place_type : std::false_type {};
template
struct is_in_place_type : std::true_type {};
// Implementation for iterating over arguments to find std::in_place_type tag and collect arguments
template
struct GetComponentArgsImpl;
// Specialization when no arguments are left, returns empty tuple
template
struct GetComponentArgsImpl {
static auto Get() {
return std::tuple();
}
};
// Specialization that collects all arguments belonging to std::in_place_type_t
// Returns a std::tuple containing said arguments
template
struct GetComponentArgsImpl {
private:
// Collect all arguments until next std::in_place_type
template
struct Collector {
template
static auto Collect(std::tuple in_collected, First&& in_first, Others&&... in_others) {
if constexpr (is_in_place_type::value) {
// Next in_place_type found, stop collecting
return in_collected;
} else {
// Collect this arg and recurse
return Collector::Collect(
std::tuple_cat(in_collected, std::forward_as_tuple(std::forward(in_first))),
std::forward(in_others)...);
}
}
// No more args
static auto Collect(std::tuple in_collected) {
return in_collected;
}
};
public:
static auto Get(const std::in_place_type_t&, Rest&&... in_rest) {
return Collector::Collect(std::tuple(), std::forward(in_rest)...);
}
};
// Specialization when encountering a std::in_place_type argument
// Skips until std::in_place_type matches type T
template
struct GetComponentArgsImpl {
private:
// Skip the args belonging to U until next std::in_place_type
template
struct Skipper {
template
static auto Skip(First&& in_first, Others&&... in_others) {
if constexpr (is_in_place_type::value
&& std::is_same_v) {
// Next tag found, recurse on get_inplace_args_impl
return GetComponentArgsImpl::Get(in_first, std::forward(in_others)...);
} else {
// Skip this arg and continue skipping
return Skipper::Skip(std::forward(in_others)...);
}
}
// No more args while skipping means T not found
static auto Skip() {
return std::tuple();
}
};
public:
static auto Get(const std::in_place_type_t&, Rest&&... in_rest) {
return Skipper::Skip(std::forward(in_rest)...);
}
};
// Unpacks an std::in_place_type argument list from parameters:
// GetComponentArgs(std::in_place_type, 1, 2, std::in_place_type, 3, 4, std::in_place_type, 5, 6);
// -> std::tuple(3, 4);
template
auto GetComponentArgs(TaggedArgs&&... in_args) {
return GetComponentArgsImpl::Get(std::forward(in_args)...);
}
struct A {};
struct B {};
struct C {};
int main() {
auto extractedArgs = GetComponentArgs(std::in_place_type, 1, 2, std::in_place_type, 3, 4, std::in_place_type, 5, 6);
std::cout Я также должен добавить, что я использую в первую очередь MSVC. Я только что заметил, что выход GCC сильно отличается от MSVC One. В идеале это работает на обоих!>
Подробнее здесь: [url]https://stackoverflow.com/questions/79684048/c-template-metaprogramming-selecting-a-range-of-arguments-from-a-parameter-p[/url]
Я делаю систему ECS с компиляцией и создал класс архетипа для хранения компонентов: < /p> [code]template class Archetype;
template struct ComponentStorage { T* data = nullptr;
Deep_Inline T* Get() const; };
template class Archetype : private ComponentStorage... { // ... } < /code> Я хочу позволить ему принимать компоненты, которые не имеют тривиальных конструкторов, но это означает, что при создании сущности мне нужно иметь возможность передавать аргументы каждому требуемому конструктору компонентов.archetype.CreateEntity(std::in_place_type, arg1, arg2, std::in_place_type, arg3, arg4); [/code] So component A is constructed being passed arg1, arg2 and B is constructed with arg3, arg4 etc... Ideally order doesn't matter as it uses the tags std::in_place_type I have a working system to extract the needed arguments using std :: tuple : [code]#include #include #include #include
// Helpers to detect if a type is std::in_place_type template struct is_in_place_type : std::false_type {}; template struct is_in_place_type : std::true_type {};
// Implementation for iterating over arguments to find std::in_place_type tag and collect arguments template struct GetComponentArgsImpl;
// Specialization when no arguments are left, returns empty tuple template struct GetComponentArgsImpl { static auto Get() { return std::tuple(); } };
// Specialization that collects all arguments belonging to std::in_place_type_t // Returns a std::tuple containing said arguments template struct GetComponentArgsImpl { private: // Collect all arguments until next std::in_place_type template struct Collector { template static auto Collect(std::tuple in_collected, First&& in_first, Others&&... in_others) { if constexpr (is_in_place_type::value) { // Next in_place_type found, stop collecting return in_collected; } else { // Collect this arg and recurse return Collector::Collect( std::tuple_cat(in_collected, std::forward_as_tuple(std::forward(in_first))), std::forward(in_others)...); } }
// No more args static auto Collect(std::tuple in_collected) { return in_collected; } };
// Specialization when encountering a std::in_place_type argument // Skips until std::in_place_type matches type T template struct GetComponentArgsImpl { private: // Skip the args belonging to U until next std::in_place_type template struct Skipper { template static auto Skip(First&& in_first, Others&&... in_others) { if constexpr (is_in_place_type::value && std::is_same_v) { // Next tag found, recurse on get_inplace_args_impl return GetComponentArgsImpl::Get(in_first, std::forward(in_others)...); } else { // Skip this arg and continue skipping return Skipper::Skip(std::forward(in_others)...); } } // No more args while skipping means T not found static auto Skip() { return std::tuple(); } };
// Unpacks an std::in_place_type argument list from parameters: // GetComponentArgs(std::in_place_type, 1, 2, std::in_place_type, 3, 4, std::in_place_type, 5, 6); // -> std::tuple(3, 4); template auto GetComponentArgs(TaggedArgs&&... in_args) { return GetComponentArgsImpl::Get(std::forward(in_args)...); }
struct A {}; struct B {}; struct C {};
int main() { auto extractedArgs = GetComponentArgs(std::in_place_type, 1, 2, std::in_place_type, 3, 4, std::in_place_type, 5, 6); std::cout Я также должен добавить, что я использую в первую очередь MSVC. Я только что заметил, что выход GCC сильно отличается от MSVC One. В идеале это работает на обоих!>