veselink1 / refl-cpp

Static reflection for C++17 (compile-time enumeration, attributes, proxies, overloads, template functions, metaprogramming).
https://veselink1.github.io/refl-cpp/md__introduction.html
MIT License
1.05k stars 76 forks source link

Member list empty when using reflect<T>(), but works fine with reflect(const T&) #80

Open hanyiabc opened 1 year ago

hanyiabc commented 1 year ago

Hi @veselink1 First of all, I would like to thank you for developing such an amazing library for C++. It has helped us a lot. While I was developing functionalities based on refl-cpp, I noticed some very strange behavior and I can't figure out where it comes from. Below are some code to reproduce the bheavior. I was trying to write an "recursiveForEach" function for nested reflected types. The code below has nothing to do with recursion as I have tried to minimize the code. Link to goldbolt

Here's the code itself.

#include <iostream>
#include <https://raw.githubusercontent.com/veselink1/refl-cpp/master/include/refl.hpp>

template<typename T, typename Func>
constexpr void forEach(T&& obj, Func&& func)
{

    refl::util::for_each(refl::reflect<T>().members, [&](auto member)
    {
        func(member(obj));
    });
}

template<typename T, typename Func>
constexpr void forEach2(T&& obj, Func&& func)
{

    refl::util::for_each(refl::reflect(obj).members, [&](auto member)
    {

        func(member(obj));

    });
}

template<typename T, typename Func>
constexpr void forEachDescriptor(Func&& func)
{

    refl::util::for_each(refl::reflect<T>().members, [&](auto member)
    {
        func(member);
    });
}

struct AAA
{
    int a, b;
};

REFL_AUTO(
    type(AAA),
    field(a),
    field(b)
)

int main()
{
    AAA a{1, 2};

    std::cout << "for each with reflct<T>()" << std::endl;
    forEach( a, [](auto && member)
    {
        std::cout << member << ',';
    });
    std::cout << std::endl;

    std::cout << "for each with reflct(const &T)" << std::endl;
    forEach2( a, [](auto && member)
    {
        std::cout << member << ',';
    });
    std::cout << std::endl;

    std::cout << "for each discriptor without passing an instance" << std::endl;
    forEachDescriptor<AAA>([](auto member)
    {
        std::cout << get_display_name(member) << ',';
    });
    std::cout << std::endl;
    std::cout << "end of program" << std::endl;
    return 0;
}

I have wrriten 3 wrappers around the for each utility from refl. The first one takes an instance of the object but uses refl::reflect<T>() to get the descriptor. The second one takes an instance of the object but uses refl::reflect(const T&) to get the descriptor. The third one does not take an instance of the object but instead, it iterate through the members using refl::reflect<T>() to get the descriptor. In theory, the three usage of reflect should hehave exactly the same but the first one will result in empty members. The third one also uses refl::reflect<T>() but different from the first funtion, it works.

When you run this code, you should see the following output

for each with reflct<T>()

for each with reflct(const &T)
1,2,
for each discriptor without passing an instance
a,b,
end of program

I have tried this on gcc 9.4, 10.2, 10.3, all resulted in the same behavior.

hanyiabc commented 1 year ago

I have found the solution. reference needs to be removed before passing into reflect std::remove_reference_t solved it.