Я работаю над каким-то простым отражением для структур С++, где я хочу рекурсивно перебирать все переменные-члены. Приведенный ниже код почти делает то, что я хочу, но мой компилятор соответствует требованиям: «рекурсивный тип или контекст зависимости функции слишком сложный», поступающий из формы aggregate_arity<MemberType>::size()
, который основан на Ориентирует реализацию агрегата_аритета.
Пример использования:
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);
Реализация:
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);
}
Я использую has_spv_tag, чтобы отметить структуры, которые должны быть отражены. Я не могу дождаться С++ 20 с реальной поддержкой отражения :(
Спасибо за вашу помощь!
Редактировать: я получил его для компиляции и изменил порядок итерации. Теперь возникает другая проблема: constexpr size_t M =aggregate_arity::size() возвращает 0 даже для того же типа, который раньше возвращал правильное значение. Я проверил, что тип фактически одинаков (первый тип структуры B), сравнив хэш с typeid. Как возможно, чтобы этот агрегат возвращал два разных значения для одного и того же типа?
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);
}
}
}
Изменить 2: пример для новой версии: http://coliru.stacked-crooked.com/a/b25a84454d53d8de
constexpr size_t M = boost::pfr::tuple_size_v<decltype(member)>;
, я получаю это приятное сообщение: error C2338: Что-то пошло не так. Пожалуйста, сообщите об этой проблеме на github вместе со структурой, которую вы отражаете. - person Fabian   schedule 13.10.2017