Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor...

77
C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer (DLL, LexicalCast, Any, TypeIndex, Conversion) + Boost.CircularBuffer, Boost.Variant

Transcript of Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor...

Page 1: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

C++14 ReflectionsWithout Macros, Markup nor External Tooling

Metaprogramming Tricks for POD Types

Antony Polukhin

Boost libraries maintainer (DLL, LexicalCast, Any, TypeIndex, Conversion)+ Boost.CircularBuffer, Boost.Variant

Page 2: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Structure (very complicated)

struct complicated_struct {

int i;

short s;

double d;

unsigned u;

};

2 / 71

Page 3: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Something that must not work...

#include <iostream>

#include "magic_get.hpp"

struct complicated_struct { /* … */ };

int main() {

using namespace pod_ops;

complicated_struct s {1, 2, 3.0, 4};

std::cout << "s == " << s << std::endl; // Compile time error?

}3 / 71

Page 4: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

But how?..

antoshkka@home:~$ ./test

s == {1, 2, 3.0, 4}

4 / 71

Page 5: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

What's in the header?

#include <iostream>

#include "magic_get.hpp"

struct complicated_struct { /* … */ };

int main() {

using namespace pod_ops;

complicated_struct s {1, 2, 3.0, 4};

std::cout << "s == " << s << std::endl; // Compile time error?

}5 / 71

Page 6: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

We need to go deeper...

template <class Char, class Traits, class T>

std::basic_ostream<Char, Traits>&

operator<<(std::basic_ostream<Char, Traits>& out, const T& value)

{

flat_write(out, value);

return out;

}

6 / 71

Page 7: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

...

template <class Char, class Traits, class T>

void flat_write(std::basic_ostream<Char, Traits>& out, const T& val) {

out << '{';

detail::flat_print_impl<0, flat_tuple_size<T>::value >::print(out, val);

out << '}';

}

7 / 71

Page 8: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

O_O

template <std::size_t FieldIndex, std::size_t FieldsCount>

struct flat_print_impl {

template <class Stream, class T>

static void print (Stream& out, const T& value) {

if (!!FieldIndex) out << ", ";

out << flat_get<FieldIndex>(value); // std::get<FieldIndex>(value)

flat_print_impl<FieldIndex + 1, FieldsCount>::print(out, value);

}

};8 / 71

Page 9: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Wow!..

/// Returns const reference to a field with index `I`

/// Example usage: flat_get<0>(my_structure());

template <std::size_t I, class T>

decltype(auto) flat_get(const T& val) noexcept;

/// `flat_tuple_size` has a member `value` that constins fields count

/// Example usage: std::array<int, flat_tuple_size<my_structure>::value > a;

template <class T>

using flat_tuple_size;

9 / 71

Page 10: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

How to count fields?

Page 11: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Idea for counting fields

static_assert(std::is_pod<T>::value, "")

11 / 71

Page 12: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Idea for counting fields

static_assert(std::is_pod<T>::value, "")

T { args... }

12 / 71

Page 13: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Idea for counting fields

static_assert(std::is_pod<T>::value, "")

T { args... }

sizeof...(args) <= fields count typeid(args)... == typeid(fields)...

13 / 71

Page 14: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Idea for counting fields

static_assert(std::is_pod<T>::value, "")

T { args... }

sizeof...(args) <= fields count typeid(args)... == typeid(fields)...

14 / 71

Page 15: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Idea for counting fields

static_assert(std::is_pod<T>::value, "")

T { args... }

sizeof...(args) <= fields count typeid(args)... == typeid(fields)...

sizeof(char) == 1

sizeof...(args) <= sizeof(T)

15 / 71

Page 16: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Idea for counting fields

static_assert(std::is_pod<T>::value, "")

T { args... }

sizeof...(args) <= fields count typeid(args)... == typeid(fields)...

sizeof(char) == 1 ???

sizeof...(args) <= sizeof(T)

16 / 71

Page 17: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Ubiq

struct ubiq {

template <class Type>

constexpr operator Type&() const;

};

int i = ubiq{};

double d = ubiq{};

char c = ubiq{};

17 / 71

Page 18: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Done!

static_assert(std::is_pod<T>::value, "")

T { args... }

sizeof...(args) <= fields count typeid(args)... == typeid(fields)...

sizeof(char) == 1 struct ubiq {}

sizeof...(args) <= sizeof(T)

18 / 71

Page 19: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Putting all together

template <std::size_t I>

struct ubiq_constructor {

template <class Type>

constexpr operator Type&() const noexcept; // Undefined

};

19 / 71

Page 20: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Putting all together

std::make_index_sequence<5>{} ===> std::index_sequence<0, 1, 2, 3, 4>{}

20 / 71

Page 21: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Putting all together

// #1

template <class T, std::size_t I0, std::size_t... I>

constexpr auto detect_fields_count(std::size_t& out, std::index_sequence<I0, I...>)

-> decltype( T{ ubiq_constructor<I0>{}, ubiq_constructor<I>{}... } )

{ out = sizeof...(I) + 1; /*...*/ }

// #2

template <class T, std::size_t... I>

constexpr void detect_fields_count(std::size_t& out, std::index_sequence<I...>) {

detect_fields_count<T>(out, std::make_index_sequence<sizeof...(I) - 1>{});

}21 / 71

Page 22: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

How to get the field type?

Page 23: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Idea #2

T{ ubiq_constructor<I>{}... }

23 / 71

Page 24: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Idea #2

T{ ubiq_constructor<I>{}... }

ubiq_constructor<I>{}::operator Type&() const

24 / 71

Page 25: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Idea #2

T{ ubiq_constructor<I>{}... }

ubiq_constructor<I>{}::operator Type&() const

Type

25 / 71

Page 26: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Idea #2

T{ ubiq_constructor<I>{}... }

ubiq_constructor<I>{}::operator Type&() const

Type

ubiq_constructor<I>{ TypeOut& }

26 / 71

Page 27: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Idea #2

T{ ubiq_constructor<I>{}... }

ubiq_constructor<I>{}::operator Type&() const

Type

ubiq_constructor<I>{ TypeOut& }

27 / 71

Page 28: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

What is a POD (roughly)?

POD = { (public|private|protected) + (fundamental | POD)* };

28 / 71

Page 29: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Idea #2.5

fundamental (not a pointer) int→

int output→

output[I]... Types...→

29 / 71

Page 30: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Putting together Idea #2

template <std::size_t I>

struct ubiq_val {

std::size_t* ref_;

template <class Type>

constexpr operator Type() const noexcept {

ref_[I] = typeid_conversions::type_to_id(identity<Type>{});

return Type{};

}

};

30 / 71

Page 31: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Putting together Idea #2

#define BOOST_MAGIC_GET_REGISTER_TYPE(Type, Index) \

constexpr std::size_t type_to_id(identity<Type>) noexcept { \

return Index; \

} \

constexpr Type id_to_type( size_t_<Index > ) noexcept { \

Type res{}; \

return res; \

} \

/**/

31 / 71

Page 32: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Putting together Idea #2

BOOST_MAGIC_GET_REGISTER_TYPE(unsigned char , 1)

BOOST_MAGIC_GET_REGISTER_TYPE(unsigned short , 2)

BOOST_MAGIC_GET_REGISTER_TYPE(unsigned int , 3)

BOOST_MAGIC_GET_REGISTER_TYPE(unsigned long , 4)

BOOST_MAGIC_GET_REGISTER_TYPE(unsigned long long , 5)

BOOST_MAGIC_GET_REGISTER_TYPE(signed char , 6)

BOOST_MAGIC_GET_REGISTER_TYPE(short , 7)

BOOST_MAGIC_GET_REGISTER_TYPE(int , 8)

BOOST_MAGIC_GET_REGISTER_TYPE(long , 9)

BOOST_MAGIC_GET_REGISTER_TYPE(long long , 10)

32 / 71

Page 33: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Putting together Idea #2

template <class T, std::size_t N, std::size_t... I>

constexpr auto type_to_array_of_type_ids(std::size_t* types) noexcept

-> decltype(T{ ubiq_constructor<I>{}... })

{

T tmp{ ubiq_val< I >{types}... };

return tmp;

}

33 / 71

Page 34: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Putting together Idea #2

template <class T, std::size_t... I>

constexpr auto as_tuple_impl(std::index_sequence<I...>) noexcept {

constexpr auto a = array_of_type_ids<T>(); // #0

return std::tuple< // #3

decltype(typeid_conversions::id_to_type( // #2

size_t_<a[I]>{} // #1

))...

>{};

}

34 / 71

Page 35: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

What about pointers to const pointers to volatile pointers to <...> fundamental type?

Page 36: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Taking care of pointers

constexpr std::size_t type_to_id(identity<Type>)

36 / 71

Page 37: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Taking care of pointers

constexpr std::size_t type_to_id(identity<Type>)

sizeof(std::size_t) * 8 == 64/32 bits

37 / 71

Page 38: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Taking care of pointers

constexpr std::size_t type_to_id(identity<Type>)

sizeof(std::size_t) * 8 == 64/32 bits

fundamental types < 32

38 / 71

Page 39: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Taking care of pointers

constexpr std::size_t type_to_id(identity<Type>)

sizeof(std::size_t) * 8 == 64/32 bits

fundamental types < 32

fundamental types require 5 bits

39 / 71

Page 40: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Taking care of pointers

constexpr std::size_t type_to_id(identity<Type>)

sizeof(std::size_t) * 8 == 64/32 bits

fundamental types < 32

fundamental types require 5 bits

not a pointer | pointer | const pointer | volatile pointer | const volatile pointer

40 / 71

Page 41: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Taking care of pointers

constexpr std::size_t type_to_id(identity<Type>)

sizeof(std::size_t) * 8 == 64/32 bits

fundamental types < 32

fundamental types require 5 bits

not a pointer | pointer | const pointer | volatile pointer | const volatile pointer

3 bits

41 / 71

Page 42: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Taking care of pointers

unsigned char c0; // 0b00000000 00000000 00000000 00000001

42 / 71

Page 43: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Taking care of pointers

unsigned char c0; // 0b00000000 00000000 00000000 00000001

unsigned char* с1; // 0b00100000 00000000 00000000 00000001

43 / 71

Page 44: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Taking care of pointers

unsigned char c0; // 0b00000000 00000000 00000000 00000001

unsigned char* с1; // 0b00100000 00000000 00000000 00000001

const unsigned char* с2; // 0b01000000 00000000 00000000 00000001

44 / 71

Page 45: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Taking care of pointers

unsigned char c0; // 0b00000000 00000000 00000000 00000001

unsigned char* с1; // 0b00100000 00000000 00000000 00000001

const unsigned char* с2; // 0b01000000 00000000 00000000 00000001

const unsigned char** с3; // 0b01000100 00000000 00000000 00000001

45 / 71

Page 46: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Taking care of pointers

unsigned char c0; // 0b00000000 00000000 00000000 00000001

unsigned char* с1; // 0b00100000 00000000 00000000 00000001

const unsigned char* с2; // 0b01000000 00000000 00000000 00000001

const unsigned char** с3; // 0b01000100 00000000 00000000 00000001

const short** s0; // 0b01000100 00000000 00000000 00000111

46 / 71

Page 47: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Taking care of pointers

template <class Type>

constexpr std::size_t type_to_id(identity<Type*>);

template <class Type>

constexpr std::size_t type_to_id(identity<const Type*>);

template <class Type>

constexpr std::size_t type_to_id(identity<const volatile Type*>);

template <class Type>

constexpr std::size_t type_to_id(identity<volatile Type*>);47 / 71

Page 48: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Taking care of pointers

template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >,

if_extension<Index, native_const_ptr_type> = 0) noexcept;

template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >,

if_extension<Index, native_ptr_type> = 0) noexcept;

template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >,

if_extension<Index, native_const_volatile_ptr_type> = 0) noexcept;

template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >,

if_extension<Index, native_volatile_ptr_type> = 0) noexcept;

48 / 71

Page 49: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Enums?

Page 50: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Enums

template <class Type>

constexpr std::size_t type_to_id(identity<Type>,

typename std::enable_if<std::is_enum<Type>::value>::type*) noexcept

{

return type_to_id(identity<

typename std::underlying_type<Type>::type

>{});

}

50 / 71

Page 51: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Nested structures and classes?

Page 52: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Nested structures and classes

template <class Type>

constexpr auto type_to_id(identity<Type>, typename std::enable_if<

!std::is_enum<Type>::value && !std::is_empty<Type>::value>::type*) noexcept

{

return array_of_type_ids<Type>(); // Returns array!

}

52 / 71

Page 53: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Nested structures and classes

// ... in struct ubiq_val

template <class Type>

constexpr operator Type() const noexcept {

constexpr auto typeids = typeid_conversions::type_to_id(identity<Type>{});

assign(typeids);

return Type{};

}

53 / 71

Page 54: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Nested structures and classes

// ... in struct ubiq_val

constexpr void assign(std::size_t val) const noexcept {

ref_[I] = val;

}

template <class T>

constexpr void assign(const T& typeids) const noexcept {

for (std::size_t i = 0; i < T::size(); ++i)

ref_[I + i] = typeids.data[i]; // ref_[I + I] must not overlap with next field

} 54 / 71

Page 55: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Space for storing type info

T { args... }

sizeof...(args) <= sizeof(T)

55 / 71

Page 56: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Space for storing type info

T { args... }

sizeof...(args) <= sizeof(T)

T needs up to sizeof(T) space for ids

56 / 71

Page 57: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Space for storing type info

T { args... }

sizeof...(args) <= sizeof(T)

T needs up to sizeof(T) space for ids

Field needs up to sizeof(Field) space for ids

57 / 71

Page 58: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Space for storing type info

T { args... }

sizeof...(args) <= sizeof(T)

T needs up to sizeof(T) space for ids

Field needs up to sizeof(Field) space for ids

I == sizeof(PrevFields) + …

I ~ offsetof(T, Field)

58 / 71

Page 59: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Space for storing type info

struct foo1 { short s; unsigned char i; }; // { 7, 0, 1, 0};

59 / 71

Page 60: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Space for storing type info

struct foo1 { short s; unsigned char i; }; // { 7, 0, 1, 0};

struct foo2 { unsigned char i; foo1 f;}; // {1, 7, 0, 1, 0, 0};

60 / 71

Page 61: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Space for storing type info

struct foo1 { short s; unsigned char i; }; // { 7, 0, 1, 0};

struct foo2 { unsigned char i; foo1 f;}; // {1, 7, 0, 1, 0, 0};

struct foo3 { foo1 f0; foo1 f; }; // {7, 0, 1, 0, 7, 0, 1, 0};

61 / 71

Page 62: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Space for storing type info

struct foo1 { short s; unsigned char i; }; // { 7, 0, 1, 0};

struct foo2 { unsigned char i; foo1 f;}; // {1, 7, 0, 1, 0, 0};

struct foo3 { foo1 f0; foo1 f; }; // {7, 0, 1, 0, 7, 0, 1, 0};

struct foo4 { foo2 f0; foo1 f; }; // {1, 7, 0, 1, 0, 0, 7, 0, 1, 0};

62 / 71

Page 63: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Nested structures and offsets

template <class T, std::size_t... I>

constexpr auto type_to_array_of_type_ids(std::size_t* types) noexcept

-> decltype(T{ ubiq_constructor<I>{}... })

{

constexpr auto offsets = get_type_offsets<T, I...>();

T tmp{ ubiq_val< offsets[I] >{types}... };

return tmp;

}

63 / 71

Page 64: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Do we need it?

Page 65: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Advantages and features:

● Comparisons : <, <=, >, >=, !=, ==● Heterogeneous comparators: flat_less<>, flat_equal<>● IO stream operators: operator <<, operator>>● Hashing: flat_hash<>● User defined serializers● Basic reflections● New type_traits: is_continuous_layout<T>, is_padded<T>, has_unique_object_representation<T>

● New features for containers: punch_hole<T, Index>● More generic algorithms: vector_mult, parse to struct

65 / 71

Page 66: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Compile times

log2(sizeof(T)) + Σ log2(sizeof(nested_structures))

In practice:● no noticeable slowdown on reasonable structures● #includes consume more time than metaprogramming stuff

66 / 71

Page 67: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Examples

namespace foo {

struct comparable_struct {

int i; short s; char data[50]; bool bl; int a,b,c,d,e,f;

};

} // namespace foo

std::set<foo::comparable_struct> s;

67 / 71

Page 68: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Examples

std::set<foo::comparable_struct> s = { /* ... */ };

std::ofstream ofs("dump.txt");

for (auto& a: s)

ofs << a << '\n';

68 / 71

Page 69: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Examples

std::set<foo::comparable_struct> s;

std::ifstream ifs("dump.txt");

foo::comparable_struct cs;

while (ifs >> cs) {

char ignore = {};

ifs >> ignore;

s.insert(cs);

}

69 / 71

Page 70: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

My favourite

template <class T>

auto flat_tie(T& val) noexcept;

struct my_struct { int i, short s; };

my_struct s;

flat_tie(s) = std::tuple<int, short>{10, 11};

70 / 71

Page 71: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Thank you! Any questions?

71 / 71

https://github.com/apolukhin/magic_get

Page 72: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

C++17 Bonus

Page 73: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

C++14

template <class T>

constexpr auto as_tuple(T& val) noexcept {

typedef size_t_<fields_count<T>()> fields_count_tag;

return detail::as_tuple_impl(val, fields_count_tag{});

}

73 / 71

Page 74: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

C++14

template <class T>

constexpr auto as_tuple(T& val) noexcept {

typedef size_t_<fields_count<T>()> fields_count_tag;

return detail::as_tuple_impl(val, fields_count_tag{});

}

74 / 71

Page 75: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Structured bindings for greater good

template <class T>

constexpr auto as_tuple_impl(T&& val, size_t_<1>) noexcept {

auto& [a] = std::forward<T>(val);

return detail::make_tuple_of_references(a);

}

template <class T>

constexpr auto as_tuple_impl(T&& val, size_t_<2>) noexcept {

auto& [a,b] = std::forward<T>(val);

return detail::make_tuple_of_references(a,b);

}75 / 71

Page 76: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Structured bindings for greater good

template <class T>

constexpr auto as_tuple_impl(T&& val, size_t_<1>) noexcept {

auto& [a] = std::forward<T>(val);

return detail::make_tuple_of_references(a);

}

template <class T>

constexpr auto as_tuple_impl(T&& val, size_t_<2>) noexcept {

auto& [a,b] = std::forward<T>(val);

return detail::make_tuple_of_references(a,b);

}76 / 71

Page 77: Without Macros, Markup nor External Tooling · C++14 Reflections Without Macros, Markup nor External Tooling Metaprogramming Tricks for POD Types Antony Polukhin Boost libraries maintainer

Thank you! Any questions?

77 / 71

https://github.com/apolukhin/magic_get