I'm working on some kind of simple reflection for c++ structs where i want to recursivly iterate over all member variables.
The code below almost does what i want but my compiler complians: "recursive type or function dependency context too complex" coming form aggregate_arity<MemberType>::size()
which is based on Orients aggregate_arity implementation.
Example usage case:
struct B
{
SPVStruct;
var_t<float2_t, true> f4;
};
struct A
{
SPVStruct;
var_t<float2_t, true> f2;
var_t<float3_t, true> f3;
float d;
B b;
};
A a{};
InitializeStruct<A, true>(a);
Implementation:
struct TSPVStructTag {};
#ifndef SPVStruct
#define SPVStruct typedef TSPVStructTag SPVStructTag;
#endif
template< class, class = std::void_t<> >
struct has_spv_tag : std::false_type { };
template< class T >
struct has_spv_tag<T, std::void_t<typename T::SPVStructTag>> : std::true_type { };
template <class T>
void InitVar(T& _Member) {}
template <class T, bool Assemble>
void InitVar(var_t<T, Assemble>& _Member)
{
// actual stuff happening here
}
template <size_t N, class T, bool Assemble>
void InitStruct(T& _Struct)
{
if constexpr(N > 0u)
{
auto& member = get<N-1>(_Struct);
using MemberType = typename std::decay_t<decltype(member)>;
if constexpr(has_spv_tag<MemberType>::value)
{
constexpr size_t n = aggregate_arity<MemberType>::size(); // this is the complex recursion that blows up
InitStruct<n, MemberType, Assemble>(member);
}
else
{
InitVar(member);
InitStruct<N - 1, T, Assemble>(_Struct);
}
}
}
template <class T, bool Assemble>
void InitializeStruct(T& _Struct)
{
constexpr size_t N = aggregate_arity<T>::size();
InitStruct<N, T, Assemble>(_Struct);
}
Example
I use the has_spv_tag to mark structs that should be reflected. I can't wait for c++20 with actual reflection support :(
Thanks for your help!
Edit: I got it to compile and changed the iteration order. Now a different problem comes up: constexpr size_t M = aggregate_arity::size() returns 0 even for the same type it returned the correct value earlier. i verified that the type is infact the same (first struct type B) by comparing the hash from typeid. How is it possible to that aggregate returns two different values for the exact same type?
template <class T, bool Assemble>
constexpr bool is_var_t(var_t<T, Assemble>& _Member) { return true; }
template <class T>
constexpr bool is_var_t(T& _Member) { return false; }
template <class T>
void InitVar(T& _Member) { std::cout << typeid(T).name() << std::endl; }
template <class T, bool Assemble>
void InitVar(var_t<T, Assemble>& _Member)
{
// actual stuff happening here
std::cout << typeid(T).name() << std::endl;
}
template <size_t n, size_t N, class T>
void InitStruct(T& _Struct)
{
std::cout << "n " << n << " N " << N << std::endl;
if constexpr(n < N)
{
decltype(auto) member = get<n>(_Struct);
using MemberType = std::remove_cv_t<decltype(member)>;
std::cout << typeid(MemberType).hash_code() << std::endl;
if (is_var_t(member))
{
InitVar(member);
InitStruct<n + 1, N, T>(_Struct);
}
else
{
constexpr size_t M = aggregate_arity<MemberType>::size();
InitStruct<0, M, MemberType>(member);
}
}
}
Edit 2: example for the new version: http://coliru.stacked-crooked.com/a/b25a84454d53d8de