Boost logo

Boost :

Subject: Re: [boost] Nasty compile time reflection and iteration for POD types using C++14 without macro
From: Antony Polukhin (antoshkka_at_[hidden])
Date: 2016-03-24 15:34:16


I've improved the implementation, now it has more functionality.

Github repo: https://github.com/apolukhin/magic_get

Changes:
* separate ready-for-inclusion header "magic_get.hpp" that depends only on
C++14 features (noo Boost deps)
* support for nested PODs
* now works with libstdc++ too
* more fundamental types supported
* improved compilation time
* now works with arrays too
* more extensions are allowed
* support for detecting volatile pointers
* added flat_ to public API (flat_get, flat_tuple_size)
* added multiple comments

TODO:
* make experiments with trivial constructible types
* more tests
* static assert non-default alignment and bit-fields
* experiments with making get<>() method constexpr
* support for empty types
* add to_tuple() method
* support for structures with references

Here's a motivating example:

#include <iostream>
#include <boost/type_index.hpp>
#include "magic_get.hpp"

struct make_my_life_harder { int i; short s; };
struct make_my_life_even_more_harder { unsigned int i1; unsigned short s1;
make_my_life_harder cr;};
struct foo {
    unsigned char i0;
    unsigned int i1;
    unsigned short i2;
    unsigned long long i3;
    unsigned char ar[2];
    int q;
    std::size_t w;
    int* p1;
    const void* p2;
    int const**const***volatile* p_crazy;
    const double d;
    make_my_life_harder hard_life;
    make_my_life_even_more_harder very_hard;
};

template <std::size_t I, class T>
void print(T& f) {
    std::cout << flat_get<I>(f) << "\t\t"
        << boost::typeindex::type_id< decltype(flat_get<I>(f)) >()
        << std::endl;
}

int main() {
    foo f {'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
        , {18, 19}
        , {20, 21, {22, 23}}
    };
    print<0>(f); print<1>(f); print<2>(f);
    print<3>(f); print<4>(f); print<5>(f);
    print<6>(f); print<7>(f); print<8>(f);
    print<9>(f); print<10>(f); print<11>(f);
    print<12>(f); print<13>(f); print<14>(f);
    print<15>(f); print<16>(f); print<17>(f);
    static_assert(tuple_size_v<foo> == 18, "failed tuple size check");

    int a[] = {0, 1, 2, 3};
    std::cout << '\n' << flat_get<1>(a) << std::endl;

    int b[2][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}};
    std::cout << flat_get<4>(b) << std::endl;

    int i = 777;
    std::cout << flat_get<0>(i) << std::endl;
}

Outputs:

A unsigned char
11 unsigned int
12 unsigned short
13 unsigned long long
B unsigned char
C unsigned char
16 int
17 unsigned long
0 int*
0 void const*
0 int const** const*** volatile*
30.1 double
18 int
19 short
20 unsigned int
21 unsigned short
22 int
23 short

1
4
777

2016-03-24 2:17 GMT+03:00 Louis Dionne <ldionne.2_at_[hidden]>:

> Antony Polukhin <antoshkka <at> gmail.com> writes:
> > [...]
> > * there's no known to me way to make get<>() method constexpr
>
> If we computed the offset at which the n-th member lies inside the struct,
> couldn't we use something like
>
> template <std::size_t I, class T>
> decltype(auto) get(const T& val) noexcept {
> std::size_t offsets[] = {}; // assume this is known
> using U = std::tuple_element_t<I, decltype(detail::as_tuple<T>())>;
> return *static_cast<U const*>( // <-- is this UB?
> static_cast<char const*>(std::addressof(val)) + offsets[I]
> );
> }
>
> Because if that works, computing the offsets is feasible.
>

I'll try that out soon.

> * does not detect constness (because of that get<>() always returns const
> > reference)
> >
> > Is there any interest in this feature?
>
> That might be interesting for Hana, while we wait for a language feature to
> make this easier.
>

On a language level this will significantly improve compilation times and
will easily remove all the implementation limitations.

-- 
Best regards,
Antony Polukhin

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk