2017-10-10 389 views
1

我正在爲C++結構體進行某種簡單的反射,我想要遞歸遍歷所有成員變量。 下面的代碼幾乎做我想要的,但我的編譯器complians:「遞歸類型或函數依賴關係上下文太複雜」來自aggregate_arity<MemberType>::size()這是基於Orients aggregate_arity implementation如何在C++中枚舉類/結構的所有成員變量

用法示例情況:

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); 
    } 

Example

我使用has_spv_tag來標記應反映結構。我不能等待C++ 20與實際的反射支持:(

感謝您的幫助

編輯: 我得到了它的編譯和改變迭代順序現在不同的問題出現了: constexpr size_t M = aggregate_arity :: size()返回0,即使是相同的類型,它返回正確的值。我通過比較來自typeid的散列來證實類型實際上是相同的(第一個結構類型B)。對於完全相同的類型,返回兩個不同的值?

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

+1

「*我不能等待C++ 20支持實際反射*」您意識到反射提議還沒有真正被批准,對吧?它可能不會成爲C++ 20。 –

+1

@NicolBolas壞消息。 – Orient

+0

@Orient我得到了編譯的代碼,但現在aggregate_arity爲同一類型返回不同的值,這怎麼可能?尼古拉波拉斯,哦,這不是很糟糕:( – Fabian

回答

0

Antony Polukhin指出了問題:MemberType仍然具有get(_Struct)的引用。該代碼

MemberType = std::remove_reference_t<std::remove_cv_t<decltype(member)>>;

template <size_t n, size_t N, class T> 
void InitStruct(T& _Struct) 
{ 
    if constexpr(n < N) 
    { 
     decltype(auto) member = get<n>(_Struct); 
     using MemberType = std::remove_reference_t<std::remove_cv_t<decltype(member)>>; 

     if constexpr(has_spv_tag<MemberType>::value) 
     { 
      InitStruct<0, aggregate_arity<MemberType>::size(), MemberType>(member); 
     } 
     else 
     { 
      InitVar(member); 
     } 
     InitStruct<n + 1, N, T>(_Struct); 
    } 
} 

工作我現在用has_spv_tag<MemberType>::value確定哪些成員是我想列舉一個結構。還有一個錯誤,訂單爲InitStruct<n + 1, N, T>(_Struct);