Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Антон Бикинеев, Reflection in C++Next

5,701 views

Published on

На протяжении всего существования C++ тема компайл-тайм рефлексии поднимается постоянно, но, к сожалению, до сих пор Стандарт языка не дает достаточных возможностей для извлечения и манипулирования компайл-тайм информацией. Большое количество библиотек и препроцессоров было придумано для того, чтобы решить эту проблему, начиная от простых макросов и заканчивая Qt-moc или ODB. В докладе Антон расскажет о том, как на эту проблему смотрит Комитет по Стандартизации: какие решения были предложены, и какое стало доминирующим.

Published in: Software
  • Be the first to comment

  • Be the first to like this

Антон Бикинеев, Reflection in C++Next

  1. 1. Reflection in C++Next Anton Bikineev, 2017
  2. 2. Agenda Reflection in C++Next 1. Reflection 2. Surviving proposals • P0194R3: Static reflection • P0590R0: A design for static reflection 3. Examples
  3. 3. Reflection or introspection? Reflection in C++Next Type introspection is the ability of a program to examine the type or properties of an object at runtime. Reflection is the ability of a computer program to examine, introspect, and modify its own structure and behavior at runtime. (from Wikipedia)
  4. 4. Reflection or introspection? Reflection in C++Next Static type introspection is the ability of a program to examine the type or properties of an object at compile-time. Static reflection is the ability of a computer program to examine, introspect, and modify its own structure and behavior at compile-time.
  5. 5. Introspection? Type traits! Reflection in C++Next namespace std { template <class T> struct is_integral { constexpr static bool value = /* */true; }; template <class T> /* since c++14 */ constexpr bool is_integral_v = is_integral<T>::value; template <class T> struct add_pointer { using type = T*; }; template <class T> using add_pointer_t = typename add_pointer<T>::type; }
  6. 6. Introspection? Type traits! Reflection in C++Next template <class Archive, class T> void load(const Archive& ar, T& t) { if constexpr (std::is_integral_v<T>) load_integral(ar, t); if constexpr (std::is_floating_point_v<T>) load_fp(ar, t); else if constexpr (std::is_trivially_copyable_v<T>) load_memset(ar, t); else load_unoptimized(ar, t); }
  7. 7. Introspection? Type traits! Reflection in C++Next template <class T, class enable = void> struct has_foo: std::false_type {}; template <class T> struct has_foo<T, std::void_t<decltype(std::declval<T>().foo())>>: std::true_type {};
  8. 8. Introspection? Type traits! Reflection in C++Next • works only with types! • no way to traverse members!
  9. 9. Reflection Reflection in C++Next Static reflection is the ability of a computer program to examine, introspect, and modify its own structure and behavior at compile-time.
  10. 10. Reflection Reflection in C++Next Static reflection is the ability of a computer program to examine, introspect, and modify its own structure and behavior at compile-time.
  11. 11. Metaprogramming definition Reflection in C++Next Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data, or that do part of the work at compile time that would otherwise be done at run-time. (from Wikipedia, some rev.)
  12. 12. C++ template metaprogramming Reflection in C++Next auto multiply_by_two(const std::array<int, 3>& array) { auto result = array; for (auto& i: result) i *= 2; return result; } std::array<int, 3> arr1{1, 2, 3}; auto arr2 = multiply_by_two(arr1);
  13. 13. C++ template metaprogramming Reflection in C++Next template <class T> struct multiply_by_two; template <class T, T... I> struct multiply_by_two<std::integer_sequence<T, I...>> { using type = std::integer_sequence<T, (I * 2)...>; }; using seq1 = std::integer_sequence<int, 1, 2, 3>; using seq2 = multiply_by_two<seq1>::type;
  14. 14. C++ constexpr metaprogramming Reflection in C++Next constexpr auto multiply_by_two(const std::array<int, 3>& array) { auto result = array; for (auto& i: result) i *= 2; return result; } constexpr std::array<int, 3> arr1{1, 2, 3}; constexpr auto arr2 = multiply_by_two(arr1);
  15. 15. Reflection? Reflection in C++Next
  16. 16. Reflection? Reflection in C++Next
  17. 17. What we actually need… Reflection in C++Next struct foo { int a; double b; string c; }; struct soa_foo { vector<int> as; vector<double> bs; vector<string> cs; };
  18. 18. Reflection in C++Next class Person { [[getter, setter]] std::string name; [[getter, setter]] std::string email; }; What we actually need…
  19. 19. Reflection in C++Next class Person { [[getter, setter, serialized]] std::string name; [[getter, setter, serialized]] std::string email; }; What we actually need…
  20. 20. Reflection in C++Next class [[polymorphically_serialized]] Person: IPerson { Person() { /* initializing code here */ } [[getter, setter, serialized]] std::string name; [[getter, setter, serialized]] std::string email; }; What we actually need…
  21. 21. Study Group 7: Reflection Reflection in C++Next • N4428: Type property queries - 4th revision - date: 2015-04-08 • P0255R0: Reflection via template pack expansion - 5th revision - date: 2016-02-12 • P0194R3: Static reflection - 7th revision - date: 2017-02-06 • P0590R0: A design for static reflection - 1st revision - date: 2017-02-05
  22. 22. Study Group 7: Reflection Reflection in C++Next • N4428: Type property queries - 4th revision - date: 2015-04-08 • P0255R0: Reflection via template pack expansion - 5th revision - date: 2016-02-12 • P0194R3: Static reflection - 7th revision - date: 2017-02-06 • P0590R0: A design for static reflection - 1st revision - date: 2017-02-05
  23. 23. Static reflection (P0194R3) Reflection in C++Next by Matúš Chochlík, Axel Naumann, David Sankel
  24. 24. P0194R3: Static reflection Reflection in C++Next • core-language changes: - operator $reflect(x); - where x is an id-expression; - returns a unique generated type for an entity x; - this type satisfies one or more concepts defined in the library; - you operate on these types (metaobjects) by calling meta- operations. • library changes: - std::reflect::Concept<m> - std::reflect::Operation<m>
  25. 25. P0194R3: Static reflection. Simple example Reflection in C++Next std::string person = "John"; using person_m = $reflect(person); static_assert(std::reflect::Variable<person_m>()); std::cout << std::reflect::get_base_name_v<person_m>;
  26. 26. P0194R3: Static reflection. Simple example Reflection in C++Next std::string person = "John"; using person_m = $reflect(person); static_assert(std::reflect::Variable<person_m>()); std::cout << std::reflect::get_base_name_v<person_m>; using type_m = std::reflect::get_type_t<person_m>; static_assert(std::reflect::Type<type_m>());
  27. 27. P0194R3: Static reflection. Simple example Reflection in C++Next std::string person = "John"; using person_m = $reflect(person); static_assert(std::reflect::Variable<person_m>()); std::cout << std::reflect::get_base_name_v<person_m>; using type_m = std::reflect::get_type_t<person_m>; static_assert(std::reflect::Type<type_m>()); using real_type = std::reflect::get_reflected_type_t<type_m>; static_assert(std::is_same_v<real_type, std::string>);
  28. 28. P0194R3: Static reflection. Meta-object concepts Reflection in C++Next namespace std::experimental::reflect { template <class T> concept bool Object(); template <class T> concept bool ObjectSequence(); template <Object T> concept bool Named(); template <Object T> concept bool Alias(); template <Object T> concept bool RecordMember(); template <Object T> concept bool Enumerator(); template <Object T> concept bool Variable(); template <Object T> concept bool ScopeMember(); template <Object T> concept bool Typed(); template <Object T> concept bool Namespace(); template <Object T> concept bool GlobalScope(); template <Object T> concept bool Class(); template <Object T> concept bool Enum(); template <Object T> concept bool Record(); template <Object T> concept bool Scope(); template <Object T> concept bool Type(); template <Object T> concept bool Constant(); template <Object T> concept bool Base(); }
  29. 29. P0194R3: Static reflection. Class-like things Reflection in C++Next template <Object T> concept bool Record(); - a union or a class template <Object T> concept bool Class(); - a class or a struct template <Object T> concept bool Base(); - base classes template <Object T> concept bool RecordMember(); - data member and member types
  30. 30. P0194R3: Static reflection. Scopes Reflection in C++Next template <Object T> concept bool Namespace(); - a namespace template <Object T> concept bool Scope(); - a namespace, class or enumeration scope template <Object T> concept bool ScopeMember(); - something in a scope template <Object T> concept bool GlobalScope(); - the global namespace, $reflect(::)
  31. 31. P0194R3: Static reflection. Enums Reflection in C++Next template <Object T> concept bool Enum(); - an enum template <Object T> concept bool Enumerator(); - an enumerator
  32. 32. P0194R3: Static reflection. Types Reflection in C++Next template <Object T> concept bool Typed(); - something that has a type, e.g. member-variable template <Object T> concept bool Type(); - a type
  33. 33. P0194R3: Static reflection. Expressions Reflection in C++Next template <Object T> concept bool Variable(); - a variable template <Object T> concept bool Constant(); - a constant-expression, like an enumerator
  34. 34. P0194R3: Static reflection. Other Reflection in C++Next template <Object T> concept bool Named(); - something with a name; template <Object T> concept bool Alias(); - an alias, like a typedef template <Object T> concept bool ObjectSequence(); - object-sequence, type-list…
  35. 35. P0194R3: Meta-object operations by examples Reflection in C++Next
  36. 36. P0194R3: Static reflection. Enum-to-string Reflection in C++Next template <class Enum> std::string to_string(Enum e) { using namespace std::reflect; using e_m = $reflect(Enum); static_assert(std::reflect::Enum<e_m>()); std::string result; for_each<get_enumerators_t<e_m>>([&](auto m) { using en_m = decltype(m); if (get_constant_v<en_m> == e) result = get_base_name_v<en_m>; }); return result; }
  37. 37. P0194R3: Static reflection. Generic equal Reflection in C++Next template <class T> bool generic_equal(const T& a, const T& b) { using namespace std::reflect; using T_m = $reflect(T); static_assert(std::reflect::Class<e_m>()); bool result = true; for_each<get_data_members_t<T_m>>([&](auto m) { using m_t = decltype(m); result &= a.*get_pointer_v<m_t> == b.*get_pointer_v<m_t>; }); return result; }
  38. 38. P0194R3: Static reflection. Generic equal with unreflect Reflection in C++Next template <class T> bool generic_equal(const T& a, const T& b) { using namespace std::reflect; using T_m = $reflect(T); static_assert(std::reflect::Class<e_m>()); bool result = true; for_each<get_data_members_t<T_m>>([&](auto m) { result &= a.$unreflect(m) == b.$unreflect(m); }); return result; }
  39. 39. P0194R3: Static reflection. Templates parametrized by namespace Reflection in C++Next namespace foo { void func1(const std::string&); void func2(int); int func3(int); } namespace bar { void func1(const std::string&); void func2(int); int func3(int); }
  40. 40. P0194R3: Static reflection. Templates parametrized by namespace Reflection in C++Next template <class MN> void algorithm(const string& str, int i) { // [foo|bar]::func1(str) $unreflect(MN)::func1(str); // [foo|bar]::func2([foo|bar]::func3(i)) $unreflect(MN)::func2($unreflect(MN)::func3(i)); } void func(const string& str, int i, bool want_foo) { if (want_foo) algorithm<$reflect(foo)>(str, i); else algorithm<$reflect(bar)>(str, i); }
  41. 41. P0194R3: Static reflection. String to identifier transformation Reflection in C++Next struct foo { int bar; }; constexpr const char* bar_name = get_base_name_v<$reflect(foo::bar)>; int get_???bar_name???(const foo&);
  42. 42. P0194R3: Static reflection. String to identifier transformation Reflection in C++Next struct foo { int bar; }; constexpr const char* bar_name = get_base_name_v<$reflect(foo::bar)>; int $identifier(ct_concat(“get_”, bar_name))(const foo&);
  43. 43. P0194R3: Static reflection. String to identifier transformation Reflection in C++Next struct foo { int a; double b; string c; }; struct soa_foo { vector<int> as; vector<double> bs; vector<string> cs; };
  44. 44. P0194R3: Static reflection Reflection in C++Next • supported: - variables; - data members; - member types; - enumerators; - template instantiations; - aliases
  45. 45. P0194R3: Static reflection Reflection in C++Next • not supported: - declarations in namespaces (except for types); - functions (yet); - class templates (yet)
  46. 46. P0194R3: Static reflection. Pros and cons Reflection in C++Next • Pros: - reflection of different entities is supported; - very lazy instantiation, only queried data is instantiated; - “you don’t pay for what you don’t use” at compile-time; - a good base for building higher-level and domain-specific libraries; - very extensible
  47. 47. P0194R3: Static reflection. Pros and cons Reflection in C++Next • Cons: - awkward and verbose usage; - no attribute ideas
  48. 48. A design for static reflection (P0590R0) Reflection in C++Next by Andrew Sutton, Herb Sutter
  49. 49. P0590R0: A design for static reflection Reflection in C++Next • core-language changes: - operator $x; - where x is an id-expression; - returns a unique object of a generated type for an entity x; - the object represents its meta information; - you operate on these objects by calling member-functions • library changes: - std::meta::reflection_type<X>
  50. 50. P0590R0: A design for static reflection. Simple example Reflection in C++Next std::string person = "John"; auto person_m = $person; static_assert(std::meta::is_variable_v< decltype(person_m)>); std::cout << person_m.name();
  51. 51. P0590R0: A design for static reflection. Simple example Reflection in C++Next std::string person = "John"; auto person_m = $person; static_assert(std::meta::is_variable_v< decltype(person_m)>); std::cout << person_m.name(); auto type_m = person_m.type(); static_assert(std::meta::is_type_v<decltype(type_m)>);
  52. 52. P0590R0: A design for static reflection. Simple example Reflection in C++Next std::string person = "John"; auto person_m = $person; static_assert(std::meta::is_variable_v< decltype(person_m)>); std::cout << person_m.name(); auto type_m = person_m.type(); static_assert(std::meta::is_type_v<decltype(type_m)>); using real_type = ???;
  53. 53. P0194R3 vs P0590R0 Enum-to-string Reflection in C++Next template <class Enum> std::string to_string(Enum e) { using namespace std::reflect; using e_m = $reflect(Enum); static_assert(std::reflect::Enum<e_m>()); std::string result; for_each<get_enumerators_t<e_m>>([&](auto m) { using en_m = decltype(m); if (get_constant_v<en_m> == e) result = get_base_name_v<en_m>; }); return result; }
  54. 54. P0194R3 vs P0590R0 Enum-to-string Reflection in C++Next template <class Enum> std::string to_string(Enum e) { using namespace std::meta; auto e_m = $Enum; static_assert(std::meta::is_enum_v<decltype(e_m)>); std::string result; for_each(e_m.enumerators(), [&](auto m) { if (m.value() == e) result = m.name(); }); return result; }
  55. 55. P0194R3 vs P0590R0 Enum-to-string Reflection in C++Next template <class Enum> std::string to_string(Enum e) { using namespace std::meta; auto e_m = $Enum; static_assert(std::meta::is_enum_v<decltype(e_m)>); std::string result; for (auto e: e_m.enumerators()) if (m.value() == e) result = m.name(); return result; }
  56. 56. P0194R3 vs P0590R0 Generic equal Reflection in C++Next template <class T> bool generic_equal(const T& a, const T& b) { bool result = true; for (auto member: $T.member_variables()) { auto ptr = member.pointer(); result &= a.*ptr == b.*ptr; } return result; }
  57. 57. P0590R0: A design for static reflection. Pros and cons Reflection in C++Next • Pros: - reflection of different entities is supported; - better syntax; - a good base for building higher-level and domain-specific libraries; - extensible
  58. 58. P0590R0: A design for static reflection. Pros and cons Reflection in C++Next • Cons: - some extra data may still be instantiated by compiler; - no attribute ideas
  59. 59. Thank you for your attention! Reflection in C++Next

×