如何在C ++中枚举类/结构的所有成员变量 [英] How to enumerate all member variables of a class / struct in c++

查看:164
本文介绍了如何在C ++中枚举类/结构的所有成员变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为c + +结构进行某种简单的反射,我想递归地迭代所有成员变量. 下面的代码几乎可以满足我的要求,但我的编译器会出错:递归类型或函数依赖上下文太复杂",基于aggregate_arity<MemberType>::size() >确定aggregate_arity的实现方式.

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.

使用案例示例:

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标记应反映的结构.我等不及具有实际反射支持的c ++ 20:(

I use the has_spv_tag to mark structs that should be reflected. I can't wait for c++20 with actual reflection support :(

感谢您的帮助!

我将其编译并更改了迭代顺序.现在出现另一个问题:constexpr size_t M = gregation_arity :: size()返回0,即使对于早先返回正确值的相同类型也是如此.通过比较来自typeid的哈希值,我验证了该类型实际上是相同的(第一个结构类型B).该聚合如何为完全相同的类型返回两个不同的值?

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

的新版本示例: http://coliru.stacked-crooked.com/a/b25a84454d53d8de

推荐答案

Antony Polukhin指出了问题:MemberType仍然具有get(_Struct)的引用.该代码适用于

Antony Polukhin pointed out the problem: MemberType still had the reference from get(_Struct). The code works with

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

I now use has_spv_tag<MemberType>::value to identify which member is a struct that i want to enumerate. There was also a bug with the order of InitStruct<n + 1, N, T>(_Struct);

这篇关于如何在C ++中枚举类/结构的所有成员变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆