Welcome to v1.0 of the meta::[[verse]]!

# Slide 1
# Slide 2
  • C++ Software Engineer, OS Internals
  • ISO C++ foundation and Boost foundation board member
  • Member of the ISO C++ Committee
    • Israeli National Body Chair
    • Library Evolution Work Group Chair

Inbal Levi

https://slides.com/inballevi/welcome-to-v1-0-of-the-meta-verse

# Slide 3

C++ Standards Committee

Reflection in C++

# Slide 4
  • The ability of software to expose its internal structure
  • Static reflection - compiler exposes structure at compile time
     
  • Disclaimers:
    • It's possible to "carry" the data into the runtime...
    • But may introduce performance, security, or other issues
    • This is out of scope for this talk (and for C++26, as of now)

This Talk

# Slide 5
  • Part I: Intro to reflection:
    1. A brief history of "Reflection" proposals in C++
    2. Latest proposal: "P2996: Reflection for C++26"
    3. Usage examples (reflection-based library) (*)
  • Part II: Impact on our code bases
    1. Reflection as a Customization Point Mechanism
    2. Pipeline integration
    3. What's next?

(*) Examples from or derive from P2996, P3096, or EDG's implementation

2006

Template-based reflection
(Matúš Chochlik)
Mirror reflection library

2012

N3403: Use Cases for Compile-Time Reflection
(Mike Spertus)

# Slide 6

2014 - 2016

N3996: Static reflection (Matúš Chochlik)

N4113, N4239, N4027, N3984
(type traits, attributes, etc.)

2015

Boost.Hana
(Louis Dionne)
Template  metaprog. lib

A Brief History

Serialization
Delegates
Getters / Setters
Customization Points

2018

P0954: What do we want to do with reflection?
(Bjarne)

2017

P0194|P0385: Static Reflection
(Matúš, Axel, David)
P0590: A design for static reflection
(Andrew, Herb)
P0633: Exploring the design space
(Daveed, Louis)

2018

N4747: Reflection TS
(David)

# Slide 7

2018

P0993: Value-based reflection
(Andrew, Herb)
P1240: Scalable Reflection in C++
(Andrew, Faisal, Daveed)

2019

P0953: constexpr reflexpr
(Matúš, Axel, David)
P1733: User-friendly and Evolution-friendly Reflection: A Compromise
(David, Daveed)

A Brief History

Typefull
vs.
Monotype

Type based
vs.
Value based

meta objects

2020

P2087: Reflection Naming: fix reflexpr
(Mihail Naydenov)
P2040: Reflection-based lazy-evaluation
(Corentin)

2021

P2320: The Syntax of Static Reflection
(Andrew, Wyatt, Daveed)
(+ implementation: lock3 meta)

2023

P2996: Reflection for C++26
(Barry, Wyatt, Peter, Andrew, Faisal, Daveed)

2022

P2560: Comparing Value- and type- based reflection
(Matus)

# Slide 8

2023

P2911: Python Bindings (...)
(Adam, Jagrut)
P3010: Using reflection (...) JS Bindings
(Dan Katz)

A Brief History

2025

P2996R11
(+Dan Katz)

(1.5 years later)

# Slide 9

What do I mean by "Reflection"?

// Lib.hpp
class LibType : public BaseOne, public BaseTwo
{
   int a;
   double b;
};
P2996
// main.cpp
#include <meta>
#include "Lib.hpp"

int main()
{
   constexpr std::meta::info refexpr = ^^LibType;
   constexpr auto res = std::meta::bases_of(refexpr)[0];
}

https://godbolt.org/z/WxdvKdcMY

# Slide 10

P2996: Reflection for C++26

  1. Reflection Operator: ^^

  2. Splicers: [::]

  3. std::meta::info

  4. Metafunctions

P2996

10. define_aggregate (inject)

  1. Name & Location:

3. Template Queries:

10. define_class (inject)

  1. identifier_of

  2. display_string_of

  3. source_location_of

  1. template_of

  2. template_arguments_of

11. Data Layout:

​4. Member Queries:

  1. offset_of -> member_offset

  2. size_of

  3. alignment_of

  4. bit_size_of

​2. Type Queries:

  1. members_of, bases_of

  2. (non)static_data_members_of

  3. accessible_members_of (P3293R2)

  4. enumerators_of

  1. type_of

  2. parent_of

  3. dealias
     

  4. Access modifiers: is_public, is_protected, is_private

  5. Inheritance: is_virtual, is_pure_virtual, is_override, ...

  6. Encapsulation: is_class_member, is_namespace_member, is_explicit, is_deleted, ...

  7. Advanced Type Queries: is_complete_type, is_template, is_special_member, ...

12. (+) Type Traits

(+ Other Type Predicates)

5. substitute (template)

6. reflect Invoke (template)

7. extract<T>(info) (constexpr not required)

8. test_type(s) ("is_same")

9. reflect_x (extended)

  1. reflect_constant

  2. reflect_object

  3. reflect_function

auto rexpr = ^ int;
# Slide 11

The Reflection Operator (^^) (Lift)

P2996

AKA Unibrow

^
auto rexpr = ^^int;
# Slide 12

The Reflection Operator (^^) (Lift)

  • Shifts expressions into a "meta" - "reflection info" object
  • Object can then to be used as input to reflection utilities

error: meta type variables must be constexpr

constexpr auto rexpr = ^^int;
P2996
# Slide 13

Splicers

  • Splice extract the C++ expression back from "meta::info"...
  • ...To be then used regularly to write the C++ program
constexpr auto rexpr = ^^int;
typename[:rexpr:] a  = 42;

What are you?

rexpr

meta::info obj, contains info on "int" type

typename[:rexpr:]

int

P2996

* More about the typename in P2996/[dcl.type.splice]

# Slide 14

P2996: Reflection for C++26

P2996
  1. Reflection Operator: ^^

  2. Splicers: [::]

  3. std::meta::info

  4. Metafunctions

  1. Name & Location:

3. Template Queries:

10. define_aggregate (inject)

  1. identifier_of

  2. display_string_of

  3. source_location_of

  1. template_of

  2. template_arguments_of

11. Data Layout:

​4. Member Queries:

  1. offset_of -> member_offset

  2. size_of

  3. alignment_of

  4. bit_size_of

​2. Type Queries:

  1. members_of, bases_of

  2. (non)static_data_members_of

  3. accessible_members_of (P3293R2)

  4. enumerators_of

  1. type_of

  2. parent_of

  3. dealias
     

  4. Access modifiers: is_public, is_protected, is_private

  5. Inheritance: is_virtual, is_pure_virtual, is_override, ...

  6. Encapsulation: is_class_member, is_namespace_member, is_explicit, is_deleted, ...

  7. Advanced Type Queries: is_complete_type, is_template, is_special_member, ...

12. (+) Type Traits

(+ Other Type Predicates)

5. substitute (template)

6. reflect Invoke (template)

7. extract<T>(info) (constexpr not required)

8. test_type(s) ("is_same")

9. reflect_x (extended)

  1. reflect_constant

  2. reflect_object

  3. reflect_function

# Slide 15

std::meta::info

From: "Let's talk about abstraction layers"

P2996
# Slide 16

std::meta::info

Represents:

  • Type and type alias
  • Function or member function
  • Variable, static data member, or structured binding
  • Non-static data member
  • Enumerators
  • Object that is a permitted result of a constant expression
  • Value with structural type that is a permitted result of a const evaluation
  • Template
  • Namespaces, namespace alias
int a = 42;
constexpr auto b = ^^a;
std::cout << [:b:] << "\n";       // OK
std::cout << [:^^(a*2):] << "\n"; // Error
constexpr int a = 42;
constexpr auto b = ^^a;
std::cout << [:b:] << "\n";       // OK
std::cout << [:^^(a*2):] << "\n"; // OK
P2996
# Slide 17

std::meta::info

#include <iostream>
#include <experimental/meta>

class R;

constexpr std::meta::info res1 = ^^R;
constexpr auto print1 = std::meta::
				is_complete_type(res1); // (1)

class R {
    int a;
};

constexpr std::meta::info res2 = ^^R;
constexpr auto print2 = std::meta::
				is_complete_type(res2); // (2)
constexpr auto print3 = std::meta::
				is_complete_type(res1); // (3)

int main()
{
    std::cout << "Res: " << print1 << "\n"; // (1)
    std::cout << "Res: " << print2 << "\n"; // (2)
    std::cout << "Res: " << print3 << "\n"; // (3)
}
P2996

https://godbolt.org/z/cafxMPo4o

# Slide 18

P2996: Reflection for C++26

P2996
  1. Reflection Operator: ^^

  2. Splicers: [::]

  3. std::meta::info

  4. Metafunctions

  1. Name & Location:

3. Template Queries:

10. define_aggregate (inject)

  1. identifier_of

  2. display_string_of

  3. source_location_of

  1. template_of

  2. template_arguments_of

11. Data Layout:

​4. Member Queries:

  1. offset_of -> member_offset

  2. size_of

  3. alignment_of

  4. bit_size_of

​2. Type Queries:

  1. members_of, bases_of

  2. (non)static_data_members_of

  3. accessible_members_of (P3293R2)

  4. enumerators_of

  1. type_of

  2. parent_of

  3. dealias
     

  4. Access modifiers: is_public, is_protected, is_private

  5. Inheritance: is_virtual, is_pure_virtual, is_override, ...

  6. Encapsulation: is_class_member, is_namespace_member, is_explicit, is_deleted, ...

  7. Advanced Type Queries: is_complete_type, is_template, is_special_member, ...

12. (+) Type Traits

(+ Other Type Predicates)

5. substitute (template)

6. reflect Invoke (template)

7. extract<T>(info) (constexpr not required)

8. test_type(s) ("is_same")

9. reflect_x (extended)

  1. reflect_constant

  2. reflect_object

  3. reflect_function

# Slide 19

Metafunctions

constexpr auto a = 42;
std::cout << meta::name_of(^^a) << "\n";

All* the metafunctions accept "info" and return:

  1. string_view (e.g. identifier_of)
  2. std::meta::info (e.g. type_of)
  3. vector<std::meta::info> (e.g. bases_of)
  4. bool (e.g. is_concept)
  5. size_t (e.g. alignment_of)
  6. T (e.g. extract(info))
  7. source_location, member_offset (e.g. offset_of)

* Besides "reflect_value/object/function", which accepts type T

P2996

https://godbolt.org/z/9YW4bWGM7

constexpr auto a = 42;
std::cout << meta::identifier_of(^^a) << "\n";
# Slide 20

Substitute

  • The equivalent "Reflection Relm" for instantiating a template
P2996
constexpr auto rexpr1 = 
	substitute(^^std::array, {^^int, reflect_value(3)});
typename[:rexpr1:] myArr1;	  // std::array<int, 3> myArr1

constexpr auto rexpr2 = 
	substitute(^^S, {^^int, 3});
typename[:rexpr2:] myArr2;	  // Fail
# Slide 21

Extract

  • The equivalent "Reflection Relm" for extracting values
P2996
constexpr auto expr1 = 
		extract<int>(reflect_value(3));	 // OK
constexpr auto expr2 = 
		extract<int>(reflect_value("3")); // Fail

# Slide 22

Type Traits

  • Two types of "Type Traits":
    • Query the type
    • Modify the type
  • P2996 proposes the first type (e.g. is_nothrow_swappable)
  • Interesting functionality available by the second type
  • ...But this is more challenging, as it interferes with the compiler's representation of the program
P2996
# Slide 23

Function Param Names

#include <experimental/meta>
#include <iostream>

consteval auto PrintParamK(std::meta::info r, size_t k) 
{
    return name_of(parameters_of(r)[k]);
}

// Function Declaration
void func(int first, int last);

void PrintFuncParamAfterDeclaration() 
{
    std::cout << "Param names: " 
    << PrintParamK(^func, 0) << ", "
    << PrintParamK(^func, 1) << "\n";
}

// Function Definition
void func(int n, int ln)
{}

void PrintFuncParamAfterDefinition() 
{
    std::cout << "Param names: "
    << PrintParamK(^func, 0) << ", "
    << PrintParamK(^func, 1) << "\n";
}


int main() 
{
    PrintFuncParamAfterDeclaration();   // Param names: first, last
    PrintFuncParamAfterDefinition();    // Param names: n, ln
}

https://godbolt.org/z/M84Ea6P88

Based on example from P3096

P2996
# Slide 24

Function Param Names

  • P3096 Introduces the following options:
    1. Compile, No Guarantees
      (Different compilers' output may be inconsistent)
    2. Enforce Consistent Naming
      (Don't compile if more than one option exists)
    3. Mark by attribute (e.g. [[canonical]])
      (Explicitly mark, otherwise ill-formed)
P2996
# Slide 25

Reflection Logger

#include <string>
#include <experimental/meta>

consteval bool LogMembers(std::meta::info type) 
{
  // Verify type is a class/struct
  // Ignore usecase of unnamed members (union/struct etc.)
  std::__report_constexpr_value(identifier_of(type).data());

  for (auto r : nonstatic_data_members_of(type)) 
  {
      std::__report_constexpr_value("\n\tmember:");
      std::__report_constexpr_value(identifier_of(r).data());
  }
  return true;
}

// User code
static_assert(LogMembers(^^Student));

https://godbolt.org/z/Yddfxdq8j

Reflection-Based Library

Based on example from EDG's CE implementation

#include <string>

struct Student 
{
  std::string name;
  int id;
};

https://drive.google.com/file/d/1SHDgRAqchwQXMopUecq0Ot5HCYYrKXta/view?usp=sharing

# Slide 26

Detour: Customization Points

Reflection as CP
  • Interaction between library code and user (*) code:
    • Virtual functions:
      • Library side: declaration of virtual functions
      • User side: overriding virtual functions 
    • Template instantiation:
      • Library side: declare a template
      • User side: instantiate template for their types
    • Provide functionality to be detected by ADL:
      • Library side: allows/expects functions by name
      • User side: declares a function within their type to be detected by ADL
    • And now - Reflection?

C++Now 2022, Cpp India 2022, CoreC++ 2022, CppCon 2023
"Customization Methods: Connecting User and C++ Library Code"

# Slide 27

Guarantees and requirements provided by the library
can be expressed as "Customization Points"

Reflection as CP

Detour: Customization Points

C++Now 2022, Cpp India 2022, CoreC++ 2022, CppCon 2023
"Customization Methods: Connecting User and C++ Library Code"

# Slide 28

Reflection as Customization

template<class_type T, structural_subtype_of<T> U> 
void LibFunc(const T& src, U& dst)
{   
  constexpr auto members = meta::data_members_of(reflexpr(src));   
  template for (constexpr meta::info a : members)
  {
    constexpr meta::info b = meta::lookup(dst, meta::name_of(a));
    dst.|b| = src.|a|;   
  }
}   // `structural_copy`

Example from "P2237: Metaprogramming" (Andrew Sutton)

C++Now 2022, Cpp India 2022, CoreC++ 2022, CppCon 2023
"Customization Methods: Connecting User and C++ Library Code"

Reflection as CP
# Slide 29
  • Interaction between library code and user(*) code
int main()
{
    type.[:get_member_i(0):] = 1;
    type.[:get_member_i(1):] = 1;

    type.[:member_named("pub"):] = 2;
    type.[:member_named("prv"):] = 2;
}

Library Code

User(*) Code

Reflection as Customization

class LibType {
public:
    int pub;
private:
    int prv;
public:
    void Print();
};
Reflection as CP
# Slide 30

Function Param Names

  • Forward competability
void PrintFuncParams() 
{
  std::cout << "Param names: " 
  << PrintParamK(^^func, 0) << ", "
  << PrintParamK(^^func, 1) << "\n";
}
void func(int first, int last);
// PrintParamsLocation1() { ... }
void func(int first, int last) 
{ ... }
// PrintParamsLocation2() { ... }

int main() 
{
  PrintFuncParamsLocation1();
  PrintFuncParamsLocation2();
}

Library Code

New User Code

void func(int first, int last);
// PrintParamsLocation1() { ... }
void func(int a, int b) 
{ ... }
// PrintParamsLocation2() { ... }

int main() 
{
  PrintFuncParamsLocation1();
  PrintFuncParamsLocation2();
}

"P3096: Function Parameter Reflection in Reflection for C++26"
 (Adam Lach, Walter Genovese)

Reflection-Based Library
# Slide 31

Pipeline Integration

Pipeline Integration

AppCode

LoggerLib

Compiler

LoggerLib.o

AppCode.o

Linker

version / macros

  • The compiler provides:
    • Standard version flag and implementation macros
  • The library can then "ifdef" based on it to figure out
    • Standard version
    • Avaliable features

main.out

# Slide 32

Pipeline Integration

Pipeline Integration

main.out

Linker

main.o

AppCode

LoggerLib

Compiler

version / macros

Linker

OldAppCode

LoggerLib

Compiler

version / macros

Backward Compatibility

# Slide 33

Detour: But what about AI?

Summary

Generate "MyTypeSerializer" class in a header (you can add .cpp file if needed), based on "MyType.h" which provide "serialize" and "deserialize" methods for "MyType", turning it into bytes buffer and back into a "MyType" class.

# Slide 34

Detour: But what about AI?

Summary
# Slide 35

Detour: But what about AI?

Summary
# Slide 36

Detour: But what about AI?

Summary
# Slide 37

Detour: But what about AI?

Summary
# Slide 38

Detour: But what about AI?

  • The process of LLMs is non-deterministic
  • There is wide veriaty in outputs
  • Giving examples or defining the template works better
  • There are no guarantees between executions
Summary

Disclaimer: as of now...

# Slide 39

Detour: But what about "Rust"?

Rust's toolkit:

  1. "macros" - variadic, used as templates, expend pre-compiler
  2. "syn" - library for injecting tokens into the AST
  3. "procedural macro" - used to process AST into AST
Summary
C++ Rust
Approach Functions & traits Token manipulation
Failure Outcome Ill-formed / Compile Compile
Error indication constexpr exception CT /RT / Tests
# Slide 40

What should we expect from "reflection libraries"?

Which guarantees we provide:

  1. No compatibility between standard versions
  2. No guarantees for existing code

Possible outcomes of "breaking the contract"

  1. Program is ill-formed (fails to compile)
  2. Program contains UB (undefined behavior)
Summary

Errors at compile time:

  • Should indicate to "reflection" stage (NOT "old" compilation)
  • Throw constexpr exceptions (Thanks to Hana Dusíková!)
  • Warnings?
# Slide 41

Reflection Libraries

Which "reflection libs" should go into the standard library?

Would love your input!

More info:

What's Next?
# Slide 42

C++ 26 Reflection

How will Reflection impact our code bases?

Summary

From: https://isocpp.org/std/status (by Herb Sutter)

# Slide 43

Thank you!

Inbal Levi
sinbal2lextra@gmail.com

linkedin.com/in/inballevi/

Thank you!

Stay in touch!

Thanks to:

  • CoreC++ user group
  • Hana Dusíková (SG7 chair)
  • Matus Chochlik
  • David Sankel
  • Corentin Jabot
  • Lewis Baker
  • Adi Shavit

Thank you for being passionate about C++!

  • Reflection Papers' authors!
    Wyatt Childers, Peter Dimov, Dan Katz, Barry Revzin, Andrew Sutton, Faisal Vali, Daveed Vandevoorde, Matus Chochlik, Herb Sutter, Bjarne Stroustrup, David Sankel, Axel Naumann, Andrei Alexandrescu, Bryce Lelbach, Michael Garland, Louis Dionne, Adam Lach, Jagrut Dave, Walter Genovese, Saksham Sharma

Welcome to v1.0 of the meta::[[verse]] - CppCon

By Inbal Levi

Welcome to v1.0 of the meta::[[verse]] - CppCon

  • 0