Nasty compile time reflection and iteration for POD types using C++14 without macro
Hello, I've come up with a trick that may be useful in Boost.Hana, Boost.Serialization or some other libraries. Here's a small motivating example: #include <cstdio> #include <boost/type_index.hpp> #include "magic.hpp" 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**** p_crazy; const double d; }; template <std::size_t I, class T> void print(T& f) { printf( "%lu\t\t%s\n", (std::size_t)get<I>(f), boost::typeindex::type_id<decltype(get<I>(f))>().pretty_name().c_str() ); } int main() { foo f {10, 11, 12, 13, {14, 15}, 16, 17, 0, 0, 0, 30.0}; 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); static_assert(tuple_size<foo>() == 12, "failed tuple size check"); } That example will output: 10 unsigned char 11 unsigned int 12 unsigned short 13 unsigned long long 14 unsigned char 15 unsigned char 16 int 17 unsigned long 0 int* 0 void const* 0 int const** const**** 30 double Core ideas: 1) We may detect the POD structure fields by the POD's constructor: template <std::size_t I> struct ubiq { std::size_t* ref_; template <class Type> constexpr operator Type() const noexcept { ref_[I] = type_to_id(identity<Type>{}); return Type{}; } }; template <class T, std::size_t... I> constexpr auto type_to_array_of_type_ids(std::size_t* types) noexcept -> decltype(T{ ubiq<I>{types}... }) { return T{ ubiq<I>{types}... }; } Here type_to_array_of_type_ids will return array with types via `types`, each element of array encodes some basic type. 2) Then we convert that array into an std::index_sequence<I...> and create a type with same layout as our POD type: template <std::size_t... I> constexpr auto as_tuple_impl(std::index_sequence<I...>) noexcept { return std::tuple< decltype( id_to_type(std::integral_constant<std::size_t, I>{}) )... >{}; } 3) Now we have a type with same layout, and we cast the structure to that type: template <std::size_t I, class T> decltype(auto) get(const T& val) noexcept { auto t = reinterpret_cast<const decltype(detail::as_tuple<T>())*>( std::addressof(val) ); return get<I>(*t); } Drawbacks: * works for POD types only (could be possibly extended to trivial constructible type) * structures with non-default alignment are not supported * step 3) contains an UB, but even without that step we're still able to get field types of the POD type and fields count * current draft implementation does no support nested PODs (could be fixed easily) * current draft implementation works only on libc++ (could be fixed easily, requires reimplementing std::tuple) * there's no known to me way to make get<>() method constexpr * does not detect constness (because of that get<>() always returns const reference) Is there any interest in this feature? Sources https://github.com/apolukhin/magic_get/blob/master/magic2.cpp Online experiments can be done here: http://coliru.stacked-crooked.com/a/c33857e566e76ce2 -- Best regards, Antony Polukhin
Including whole email so context is not lost: On Tue, Mar 22, 2016 at 1:33 PM, Antony Polukhin <antoshkka@gmail.com> wrote:
Hello,
I've come up with a trick that may be useful in Boost.Hana, Boost.Serialization or some other libraries.
Here's a small motivating example:
#include <cstdio> #include <boost/type_index.hpp> #include "magic.hpp"
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**** p_crazy; const double d; };
template <std::size_t I, class T> void print(T& f) { printf( "%lu\t\t%s\n", (std::size_t)get<I>(f),
boost::typeindex::type_id<decltype(get<I>(f))>().pretty_name().c_str() ); }
int main() { foo f {10, 11, 12, 13, {14, 15}, 16, 17, 0, 0, 0, 30.0}; 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); static_assert(tuple_size<foo>() == 12, "failed tuple size check"); }
That example will output:
10 unsigned char 11 unsigned int 12 unsigned short 13 unsigned long long 14 unsigned char 15 unsigned char 16 int 17 unsigned long 0 int* 0 void const* 0 int const** const**** 30 double
Core ideas:
1) We may detect the POD structure fields by the POD's constructor:
template <std::size_t I> struct ubiq { std::size_t* ref_;
template <class Type> constexpr operator Type() const noexcept { ref_[I] = type_to_id(identity<Type>{}); return Type{}; } };
template <class T, std::size_t... I> constexpr auto type_to_array_of_type_ids(std::size_t* types) noexcept -> decltype(T{ ubiq<I>{types}... }) { return T{ ubiq<I>{types}... }; }
Here type_to_array_of_type_ids will return array with types via `types`, each element of array encodes some basic type.
2) Then we convert that array into an std::index_sequence<I...> and create a type with same layout as our POD type:
template <std::size_t... I> constexpr auto as_tuple_impl(std::index_sequence<I...>) noexcept { return std::tuple< decltype( id_to_type(std::integral_constant<std::size_t, I>{}) )... >{}; }
3) Now we have a type with same layout, and we cast the structure to that type:
template <std::size_t I, class T> decltype(auto) get(const T& val) noexcept { auto t = reinterpret_cast<const decltype(detail::as_tuple<T>())*>( std::addressof(val) ); return get<I>(*t); }
Drawbacks: * works for POD types only (could be possibly extended to trivial constructible type) * structures with non-default alignment are not supported * step 3) contains an UB, but even without that step we're still able to get field types of the POD type and fields count * current draft implementation does no support nested PODs (could be fixed easily) * current draft implementation works only on libc++ (could be fixed easily, requires reimplementing std::tuple) * there's no known to me way to make get<>() method constexpr * does not detect constness (because of that get<>() always returns const reference)
Is there any interest in this feature?
This is really cool. Yes, absolutely this is interesting. Specifically, we do a lot of bare-metal interfacing, and primitive serialization -- it would be great to generate "reports" of what is physically serialized to catch differences across versions. Also, many serialization optimizations are possible if we confirm the native types are the "same" on the two sides (e.g., "fwrite(outfile, &my_pod)" rather than marshaling each member specifically). This could be a runtime comparison of the "generated-reports", followed by an "optimized" call (if both reports are the same), or an "each-member conversion" call (if the reports are different). Loving the compile-time reflection. I think I could use your approach at both compile-time and at runtime to select most-efficient implementations. --charley
In my head, lambdas are basically just pods that capture data in their constructor. Obviously this is not exactly the case, but I think it's more or less accurate. It would probably require some language tweaks to get it to work with lambdas, but if we could it might be extremely useful. my_assert( x < 5 ); x < 5 would be the body of a &-capture lambda We reflect the (theoretical) lambda constructor to find that the lambda captured an int& Use implementation-specific knowledge to get a pointer to x And can print the actual value of x when the assertion fails Assertion Failed: x<5 where x=10 On Tue, Mar 22, 2016 at 2:45 PM, charleyb123 . <charleyb123@gmail.com> wrote:
Including whole email so context is not lost:
On Tue, Mar 22, 2016 at 1:33 PM, Antony Polukhin <antoshkka@gmail.com> wrote:
Hello,
I've come up with a trick that may be useful in Boost.Hana, Boost.Serialization or some other libraries.
Here's a small motivating example:
#include <cstdio> #include <boost/type_index.hpp> #include "magic.hpp"
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**** p_crazy; const double d; };
template <std::size_t I, class T> void print(T& f) { printf( "%lu\t\t%s\n", (std::size_t)get<I>(f),
boost::typeindex::type_id<decltype(get<I>(f))>().pretty_name().c_str() ); }
int main() { foo f {10, 11, 12, 13, {14, 15}, 16, 17, 0, 0, 0, 30.0}; 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); static_assert(tuple_size<foo>() == 12, "failed tuple size check"); }
That example will output:
10 unsigned char 11 unsigned int 12 unsigned short 13 unsigned long long 14 unsigned char 15 unsigned char 16 int 17 unsigned long 0 int* 0 void const* 0 int const** const**** 30 double
Core ideas:
1) We may detect the POD structure fields by the POD's constructor:
template <std::size_t I> struct ubiq { std::size_t* ref_;
template <class Type> constexpr operator Type() const noexcept { ref_[I] = type_to_id(identity<Type>{}); return Type{}; } };
template <class T, std::size_t... I> constexpr auto type_to_array_of_type_ids(std::size_t* types) noexcept -> decltype(T{ ubiq<I>{types}... }) { return T{ ubiq<I>{types}... }; }
Here type_to_array_of_type_ids will return array with types via `types`, each element of array encodes some basic type.
2) Then we convert that array into an std::index_sequence<I...> and create a type with same layout as our POD type:
template <std::size_t... I> constexpr auto as_tuple_impl(std::index_sequence<I...>) noexcept { return std::tuple< decltype( id_to_type(std::integral_constant<std::size_t, I>{}) )... >{}; }
3) Now we have a type with same layout, and we cast the structure to that type:
template <std::size_t I, class T> decltype(auto) get(const T& val) noexcept { auto t = reinterpret_cast<const decltype(detail::as_tuple<T>())*>( std::addressof(val) ); return get<I>(*t); }
Drawbacks: * works for POD types only (could be possibly extended to trivial constructible type) * structures with non-default alignment are not supported * step 3) contains an UB, but even without that step we're still able to get field types of the POD type and fields count * current draft implementation does no support nested PODs (could be fixed easily) * current draft implementation works only on libc++ (could be fixed easily, requires reimplementing std::tuple) * there's no known to me way to make get<>() method constexpr * does not detect constness (because of that get<>() always returns const reference)
Is there any interest in this feature?
This is really cool. Yes, absolutely this is interesting.
Specifically, we do a lot of bare-metal interfacing, and primitive serialization -- it would be great to generate "reports" of what is physically serialized to catch differences across versions. Also, many serialization optimizations are possible if we confirm the native types are the "same" on the two sides (e.g., "fwrite(outfile, &my_pod)" rather than marshaling each member specifically). This could be a runtime comparison of the "generated-reports", followed by an "optimized" call (if both reports are the same), or an "each-member conversion" call (if the reports are different).
Loving the compile-time reflection. I think I could use your approach at both compile-time and at runtime to select most-efficient implementations.
--charley
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
That looks pretty cool. This could be useful in Fit as well for fit::unpack. * there's no known to me way to make get<>() method constexpr
On gcc and clang, you could try something like this: #define CONST_FOLD(x) (__builtin_constant_p(x) ? (x) : (x)) template <std::size_t I, class T> constexpr decltype(auto) get(const T& val) noexcept { auto t = CONST_FOLD(reinterpret_cast<const decltype(detail::as_tuple<T>())*>( std::addressof(val) )); return get<I>(*t); } Of course, this requires the user to always use `CONST_FOLD` when calling get as well. There might be a better way. Paul
-- Best regards, Antony Polukhin
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Antony Polukhin <antoshkka <at> gmail.com> writes:
Hello,
I've come up with a trick that may be useful in Boost.Hana, Boost.Serialization or some other libraries.
Definitely an interesting and novel trick. Although, as you said, it is a nasty trick, and such things would be better if supported in the language (IMO). Until then, this trick might be useful.
[...] * 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.
* 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. Louis
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@gmail.com>:
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
Am 24.03.2016 um 20:34 schrieb Antony Polukhin:
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
I found a way to get a type_name type at compile type, i.e. a template which has a sequence of chars representing the type. This could be added to boost.type_index and would allow constexpr sorting of types by names etc. E.g. making boost::variant<int, double> and boost::variant<double, int> the same, by ordering the arguments alphabetically. Has lot of compiler overhead though. That might also be a workaround for the REGISTER_TYPE thing in you magic get, though I have to admit: I don't really get how this approach works, so I don't know. Here's the code for that (would need some polishing for sure), I've built it with Gcc 6. Don't know if other compiler play along with that. #include <iostream> #include <array> #include <type_traits> #include <boost/type_index.hpp> #include <tuple> using namespace std; template<char ...C> struct char_seq {}; template<std::size_t ... Idx> struct index_seq { }; template<typename T, std::size_t Append> struct append; template<std::size_t ...indexes, std::size_t Append> struct append<index_seq<indexes...>, Append> { using type = index_seq<indexes ..., Append>; }; template<typename T, std::size_t Append> using append_t = typename append<T, Append>::type; template<std::size_t Size, std::size_t Counter = 0, typename T = index_seq<>> struct make_index_seq { typedef typename make_index_seq<Size, Counter+1, append_t<T, Counter>>::type type; }; template<std::size_t Size, typename T> struct make_index_seq<Size, Size, T> { typedef T type; }; template<std::size_t Size> using make_index_seq_t = typename make_index_seq<Size>::type; template<char c> struct char_entry {}; template<typename T> struct constexpr_ti { template<std::size_t Index> constexpr static char step() { return __PRETTY_FUNCTION__[Index]; } template<std::size_t ...Indexes> constexpr static auto impl(index_seq<Indexes...> * = nullptr) { return char_seq<step<Indexes>()...>(); } constexpr static auto make() { //the 37 is determined by hand using idx_seq = make_index_seq_t<sizeof(__PRETTY_FUNCTION__)+ 37> *; return impl(idx_seq()); } }; template<typename T> constexpr auto make_type_idx() { return constexpr_ti<T>::make(); } template<char ...C> void print(char_seq<C...>) { std::array<char, sizeof...(C) + 1> arr = {C..., '\0'}; cout << arr.data() << endl; } int main() { using boost::typeindex::type_id; constexpr auto x = make_type_idx<std::tuple<int, double, void*>>(); { using t = make_index_seq_t<12>; cout << type_id<t>().pretty_name() << endl; } { using t = decltype(x); cout << type_id<t>().pretty_name() << endl; } print(x); return 0; }
2016-03-25 2:03 GMT+03:00 Klemens Morgenstern <klemens.morgenstern@gmx.net>:
I found a way to get a type_name type at compile type, i.e. a template which has a sequence of chars representing the type. This could be added to boost.type_index and would allow constexpr sorting of types by names etc. E.g. making boost::variant<int, double> and boost::variant<double, int> the same, by ordering the arguments alphabetically. Has lot of compiler overhead though.
I've tried to use __PRETTY_FUNCTION__ directly a year or two ago. Some compilers allowed that, some not. Could you try to compile that code on Clang? If that works, try to mark detail::ctti<T>::n() with constexpr and use in your code: template<std::size_t Index> constexpr static char step() { return detail::ctti<T>::n()[Index]; } If that works, then it would be a really great addition to type_index! That might also be a workaround for the REGISTER_TYPE thing in you magic
get, though I have to admit: I don't really get how this approach works, so I don't know.
That won't help. I need a way to make conversion of T type to some non-templated class and back: T -> int -> T TypeIndex allows only the first part of that: T -> type_index, but does not allow type_index -> T -- Best regards, Antony Polukhin
I've tried to use __PRETTY_FUNCTION__ directly a year or two ago. Some compilers allowed that, some not.
Could you try to compile that code on Clang? If that works, try to mark detail::ctti<T>::n() with constexpr and use in your code:
Clang 3.8 does compile with the example code.
template<std::size_t Index> constexpr static char step() { return detail::ctti<T>::n()[Index]; }
If that works, then it would be a really great addition to type_index!
That probably won't work. Constexpr [] on a const char* seems not to work, while "xyz"[1] works. That's why I use the __PRETTY_FUNC__ directly. Can be implemented that way though.
That won't help. I need a way to make conversion of T type to some non-templated class and back: T -> int -> T
TypeIndex allows only the first part of that: T -> type_index, but does not allow type_index -> T
Ah sure. Yeah then you can't get around some form of a macro. But maybe you could remove the index number, so adding a new class would work without that. That would allow me to add types at several places, because elsewise it might crash when different libraries do that. Though that would be a tweak later on.
2016-03-25 14:36 GMT+03:00 Klemens Morgenstern <klemens.morgenstern@gmx.net> :
I've tried to use __PRETTY_FUNCTION__ directly a year or two ago. Some
compilers allowed that, some not.
Could you try to compile that code on Clang? If that works, try to mark detail::ctti<T>::n() with constexpr and use in your code:
Clang 3.8 does compile with the example code.
template<std::size_t Index> constexpr static char step() { return detail::ctti<T>::n()[Index]; }
If that works, then it would be a really great addition to type_index!
That probably won't work. Constexpr [] on a const char* seems not to work, while "xyz"[1] works. That's why I use the __PRETTY_FUNC__ directly. Can be implemented that way though.
I've tired the following: #include <boost/current_function.hpp> #include <iostream> template <class T> struct ctti { static constexpr const char* n() noexcept { return BOOST_CURRENT_FUNCTION + 5; } }; int main() { constexpr auto c = ctti<int>::n() + 10; std::cerr << c; } And that worked on GCC5.3 and Clang3.7. Looks like it's time to continue the work on https://github.com/apolukhin/type_index/tree/constexpr14 and make the type_index constexpr :)
That won't help. I need a way to make conversion of T type to some
non-templated class and back: T -> int -> T
TypeIndex allows only the first part of that: T -> type_index, but does not allow type_index -> T
Ah sure. Yeah then you can't get around some form of a macro. But maybe you could remove the index number, so adding a new class would work without that. That would allow me to add types at several places, because elsewise it might crash when different libraries do that. Though that would be a tweak later on.
Actually you do not need to add types. The code must work with any POD type as member types are either 1) fundamental types (that are registered) 2) or PODs, then goto step 1) for that member -- Best regards, Antony Polukhin
I've tired the following:
#include <boost/current_function.hpp> #include <iostream>
template <class T> struct ctti { static constexpr const char* n() noexcept { return BOOST_CURRENT_FUNCTION + 5; } };
int main() { constexpr auto c = ctti<int>::n() + 10; std::cerr << c; }
Ok, might be possible. But you still get problems when passing const char* as a template parameter which you still would need to do in order to get the type. I.e. I can't use a null-terminated string, but need an array of chars and it's size.
And that worked on GCC5.3 and Clang3.7. Looks like it's time to continue the work on https://github.com/apolukhin/type_index/tree/constexpr14 and make the type_index constexpr :)
Ah, then I'll redirect my PR.
Actually you do not need to add types. The code must work with any POD type as member types are either 1) fundamental types (that are registered) 2) or PODs, then goto step 1) for that member
Oh, I thought you'd need to register POD-Types. What about enumerators?
Hi, You may want to check out our (Mine and Jonathan Müller's) CTTI library, which already implements that constexpr type_id, supporting GCC 5.X, Clang, and VS2015 https://github.com/Manu343726/ctti (This post may also add some context http://manu343726.github.io/2016/03/13/the-road-for-reflection-tagging-types... ) I will be glad to give you some feedback on this. El vie., 25 de marzo de 2016 18:04, Klemens Morgenstern < klemens.morgenstern@gmx.net> escribió:
I've tired the following:
#include <boost/current_function.hpp> #include <iostream>
template <class T> struct ctti { static constexpr const char* n() noexcept { return BOOST_CURRENT_FUNCTION + 5; } };
int main() { constexpr auto c = ctti<int>::n() + 10; std::cerr << c; }
Ok, might be possible. But you still get problems when passing const char* as a template parameter which you still would need to do in order to get the type. I.e. I can't use a null-terminated string, but need an array of chars and it's size.
And that worked on GCC5.3 and Clang3.7. Looks like it's time to continue the work on https://github.com/apolukhin/type_index/tree/constexpr14 and make the type_index constexpr :)
Ah, then I'll redirect my PR.
Actually you do not need to add types. The code must work with any POD
type
as member types are either 1) fundamental types (that are registered) 2) or PODs, then goto step 1) for that member
Oh, I thought you'd need to register POD-Types. What about enumerators?
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
2016-03-25 20:50 GMT+03:00 Manu Sánchez <manu343726@gmail.com>:
Hi,
You may want to check out our (Mine and Jonathan Müller's) CTTI library, which already implements that constexpr type_id, supporting GCC 5.X, Clang, and VS2015
https://github.com/Manu343726/ctti
(This post may also add some context
http://manu343726.github.io/2016/03/13/the-road-for-reflection-tagging-types... )
I will be glad to give you some feedback on this.
Thanks, the information about workarounds for GCC's ICE really helped! Meanwhile, I've updated the magic_get library https://github.com/apolukhin/magic_get * now works with enums too * more compile time assertions with useful notes * more useful methods (flat_get<>() that returns non-const reference if possible, flat_make_tuple, flat_tie) * added some docs and examples to the repo -- Best regards, Antony Polukhin
2016-03-25 20:04 GMT+03:00 Klemens Morgenstern <klemens.morgenstern@gmx.net> :
And that worked on GCC5.3 and Clang3.7.
Looks like it's time to continue the work on https://github.com/apolukhin/type_index/tree/constexpr14 and make the type_index constexpr :)
Ah, then I'll redirect my PR.
Looks like it's almost done. I'll try to add workaround for GCC's ICE https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66460
Actually you do not need to add types. The code must work with any POD type
as member types are either 1) fundamental types (that are registered) 2) or PODs, then goto step 1) for that member
Oh, I thought you'd need to register POD-Types. What about enumerators?
Just added some support for them. Enums are represented by underlying type (not the best solution, but at least usable). -- Best regards, Antony Polukhin
Another set of changes https://github.com/apolukhin/magic_get: * committed the previously mentioned changes (forget to do that last time) * fixed and improved flat_tuple_element and flat_tuple_size * added cool examples (comparison operators for any POD types and `ostream& operator<<` for any POD type) -- Best regards, Antony Polukhin
AMDG On 03/25/2016 12:39 AM, Antony Polukhin wrote:
2016-03-25 2:03 GMT+03:00 Klemens Morgenstern <klemens.morgenstern@gmx.net>:
That might also be a workaround for the REGISTER_TYPE thing in you magic get, though I have to admit: I don't really get how this approach works, so I don't know.
That won't help. I need a way to make conversion of T type to some non-templated class and back: T -> int -> T
Does any C++14 compiler allow the friend function registration hack? template<int I> struct id_ {}; template<int I, class T> struct register_type { friend T lookup(id_<I>); }; (I'm pretty sure that this won't work on clang.)
TypeIndex allows only the first part of that: T -> type_index, but does not allow type_index -> T
In Christ, Steven Watanabe
participants (8)
-
Antony Polukhin
-
Brent Friedman
-
charleyb123 .
-
Klemens Morgenstern
-
Louis Dionne
-
Manu Sánchez
-
Paul Fultz II
-
Steven Watanabe