CppCon 2016: "C++14 Reflections Without Macros, Markup nor External Tooling.."

By: CppCon

203   7   14646

Uploaded on 10/08/2016

http://CppCon.org

Presentation Slides, PDFs, Source Code and other presenter materials are available at: https://github.com/cppcon/cppcon2016

C++ was lacking the reflections feature for a long time. But a new metaprogramming trick was discovered recently: we can get some information about POD structure by probing it's braced initializes. Combining that trick with variadic templates, constexpr functions, implicit conversion operators, SFINAE, decltype and integral constants we can count structure's fields and even deduce type of each field.

Now the best part: everything works without any additional markup nor macros typically needed to implement reflections in C++.

In this talk I'll explain most of the tricks in detail, starting from a very basic implementation that is only capable of detecting fields count and ending up with a fully functional prototype capable of dealing with nested PODs, const/volatile qualified pointers, pointers-to-pointers and enum members. Highly useful use-cases will be shown a the end of the talk. You may start experimenting right now using the implementation at https://github.com/apolukhin/magic_get.

Antony Polukhin
Yandex
Hi, I'm Antony Polukhin, the author of Boost.TypeIndex and Boost.DLL libraries; maintainer of the Boost.LexicalCast, Boost.Any, Boost.Variant and Boost.Conversion libraries. I'm also the author of of the "Boost C++ Application Development Cookbook"

Videos Filmed & Edited by Bash Films: http://www.BashFilms.com

Comments (8):

By anonymous    2017-09-20

The pragmatic C++-way of printing an object is defining a friend function:

std::ostream& operator<<(std::ostream& os, const Point& point) {
    return os << "(" << point.x << "," << point.y << ")";
}

It's usually class-specific so you need to implement it yourself; however, you might use some form of reflection. Particularly interesting is a CppCon-talk from Antony Polukhin [1] which gives reflection for POD types (like Point above). Generic reflection without external tools is N/A yet (as of 2016), there's a proposal on it. If you can't / don't want to wait, you can do multiple things:

  1. Parse C++ code: ctags comes to mind.

  2. Macros: It's relatively easy to write a FIELDS macro that defines a reflection class and the fields.


FIELDS(
    (int)x,
    (int)y
)

  1. Tuples: Works only if you define all your fields on the same inheritance level. Inherit privately from a std::tuple<> which contains all your fields. Make const and optionally non-const getters for fields in terms of std::get<>. Then you can iterate over the types of your tuple.

(Would love to add more - pls. write comments if you have ideas.)

All the reflection methods also give you operator==() basically for free. Note that it's more pragmatic to add operator<() when possible. The former can be defined in terms of the first (albeit suboptimally: a == b iff !(a < b) && !(b < a) ) and the latter gives you std::set<> and std::map<>. Or you can do all the comparisons in terms of reflection.

[1] https://www.youtube.com/watch?v=abdeAew3gmQ

Original Thread

By anonymous    2017-09-20

Indeed, Antony Polukhin has shown us that C++ does have reflection, since C++14, without knowing it; and that you can extract information about the fields. ... well, at least for plain-old-data structs/classes. Watch his CppCon 2016 talk:

C++14 Reflections Without Macros, Markup nor External Tooling / Antony Polukhin

And then you write:

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;      /*...*/ }

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

which gets you the field count. Of course, you also need the cleverly-conceived ubiq structure. What you actually need to use is these two file:

https://github.com/apolukhin/magic_get/blob/develop/include/boost/pfr/detail/config.hpp
https://github.com/apolukhin/magic_get/blob/develop/include/boost/pfr/detail/fields_count.hpp

and that should be enough.

Original Thread

By anonymous    2017-10-15

Not an answer to your problem but probably highly related: There exists an early-stage [library for reflection without macros](https://github.com/apolukhin/magic_get) with techniques explained in a [conference talk recording](https://www.youtube.com/watch?v=abdeAew3gmQ).

Original Thread

By anonymous    2018-01-29

If you want something generic, take a look at magic_get [cppcon talk](https://www.youtube.com/watch?v=abdeAew3gmQ), [github repo](https://github.com/apolukhin/magic_get)

Original Thread

By anonymous    2018-02-26

@GuillaumeRacicot: Thanks for the link to **magic_get**. I was looking for that. Here is the [talk at CppCon](https://www.youtube.com/watch?v=abdeAew3gmQ) that explains it in great details.

Original Thread

By anonymous    2018-04-08

You can check this guy's solution - https://www.youtube.com/watch?v=abdeAew3gmQ&t=950s - but it has it's limitations.

Original Thread

Popular Videos 32000

Submit Your Video

If you have some great dev videos to share, please fill out this form.