59
Reflection in C++Next Anton Bikineev, 2017

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

Embed Size (px)

Citation preview

Reflection in C++NextAnton Bikineev, 2017

Agenda

Reflection in C++Next

1. Reflection 2. Surviving proposals

• P0194R3: Static reflection • P0590R0: A design for static reflection

3. Examples

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)

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.

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;}

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);}

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 {};

Introspection? Type traits!

Reflection in C++Next

• works only with types! • no way to traverse members!

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.

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.

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.)

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);

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;

C++ constexpr metaprogramming

Reflection in C++Next

constexprauto 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);

Reflection?

Reflection in C++Next

Reflection?

Reflection in C++Next

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;};

Reflection in C++Next

class Person{ [[getter, setter]] std::string name; [[getter, setter]] std::string email;};

What we actually need…

Reflection in C++Next

class Person{ [[getter, setter, serialized]] std::string name; [[getter, setter, serialized]] std::string email;};

What we actually need…

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…

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

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

Static reflection (P0194R3)

Reflection in C++Next

by Matúš Chochlík, Axel Naumann,

David Sankel

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>

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>;

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>());

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>);

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();}

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

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(::)

P0194R3: Static reflection. Enums

Reflection in C++Next

template <Object T> concept bool Enum();- an enum

template <Object T> concept bool Enumerator();- an enumerator

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

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

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…

P0194R3: Meta-object operations by

examples

Reflection in C++Next

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;}

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;}

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;}

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);}

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);}

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&);

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&);

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;};

P0194R3: Static reflection

Reflection in C++Next

• supported: - variables; - data members; - member types; - enumerators; - template instantiations; - aliases

P0194R3: Static reflection

Reflection in C++Next

• not supported: - declarations in namespaces (except for types); - functions (yet); - class templates (yet)

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

P0194R3: Static reflection. Pros and cons

Reflection in C++Next

• Cons: - awkward and verbose usage; - no attribute ideas

A design for static reflection (P0590R0)

Reflection in C++Next

by Andrew Sutton, Herb Sutter

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>

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();

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)>);

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 = ???;

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;}

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;}

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;}

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;}

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

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

Thank you for your attention!

Reflection in C++Next