felixguendling / cista

Cista is a simple, high-performance, zero-copy C++ serialization & reflection library.
https://cista.rocks
MIT License
1.78k stars 113 forks source link

reflection does not work with __attribute__((packed)); #102

Closed lbckmnn closed 3 years ago

lbckmnn commented 3 years ago

Hey, I am trying to reflect a packed struct but unfortunately that does not seem to work. Minimal example:

#include <cista/reflection/for_each_field.h>
#include <cista/reflection/to_tuple.h>

#include <iostream>
struct Test {
    int a;
    int b;
    int c;
} __attribute__((packed));

int main() {
    Test test;
    test.a = 3;
    test.b = 4;
    test.c = 5;

    cista::for_each_field(test, [&](auto&& m) { std::cout << m << std::endl; });
}

The error is:

...
error: cannot bind packed field 'p1' to 'int&'
...

So the underlying issue seems to be that it is not possible to bind a member of a packed struct to a reference. If i remove the attribute((packed)) it works just fine.

I guess there is not much we can do about it?

felixguendling commented 3 years ago

It seems like it's not possible to bind to a reference. However, using pointers seems to work:

#include "cista.h"

struct Test {
    int a;
    int b;
    int c;
} __attribute__((packed));

template <typename T, typename Fn>
void for_each_field_ptr(T&& t, Fn&& fn) {
  std::apply([&](auto&&... field_ptr) {
    (fn(field_ptr), ...);
  }, cista::to_ptr_tuple(t));
}

int main() {
  for_each_field_ptr(Test{3, 4, 5}, [](auto* f) {
    printf("%d\n", *f);
  });
}

https://wandbox.org/permlink/PMV2GLvuQBHaJmEi

lbckmnn commented 3 years ago

thanks! interestingly, using #pragma pack also seems to work:

#include "cista.h"

#include <iostream>
#pragma pack(push, 1)
struct Test {
    int a;
    int b;
    short int c;
    int d;
};
#pragma pack(pop)

int main() {
    Test test;
    test.a = 3;
    test.b = 4;
    test.c = 5;
    test.d = 17;

    cista::for_each_field(test, [&](auto&& m) { std::cout << +m << std::endl; });
}