Programming Languages: Reflection in C++26 | Heise Online

0
17
Programming Languages: Reflection in C++26 | Heise Online


Reflection is the ability to examine, consider, and change the structure and behavior of a program.

Advertisement




C++ has more reflection. Here are two statements from the proposal (P2996R5,




Rainer Grimm has been working as a software architect, team and training manager for many years. He enjoys writing articles on the programming languages ​​C++, Python and Haskell, but also frequently speaking at specialist conferences. On his blog Modern C++ he discusses his passion C++ in depth.

A Malaga company has developed an app to be able to “play” musicA Malaga company has developed an app to be able to “play” music

,We not only want to observe the structure of the program: we also want to make it easy to generate code that relies on those observations. That combination is sometimes referred to as “reflective metaprogramming”, but within the WG21 discussion the term “reflection” is often used informally to refer to the same general idea.,

,As far as reflection and compile-time metaprogramming are concerned, this proposal is not intended to be the end game. Instead, we expect it to be a useful core around which more powerful features will be added over time. In particular, we believe that most or all of the remaining features have been discovered in P1240R2 and that code injection (according to the lines described inP2237R0)) are the desirable directions to follow.,

The history of reflection in C++ is based on template metaprogramming. Template metaprogramming started around 1994, as did reflection. C++98 received runtime reflection (RTTI) and this function template type deduction. The data type library in C++11 improved the capabilities of C++. In C++26 we will probably get general reflection support.

I will rely on proposal P2996R5 and use the examples from proposal P2996R5 when introducing reflection in C++26.

First, I want to go back and forth from reflection value to grammatical elements.

The following program starts in the grammatical area, goes to the reflection area and comes back to the grammatical area.

// forthAndBack.cpp (P2996R5)

#include 
#include 
#include 

int main() {
    constexpr auto r = ^int;
    typename(:r:) x = 42;       // Same as: int x = 42;
    typename(:^char:) c = '*';  // Same as: char c = '*';

    static_assert(std::same_as);
    static_assert(std::same_as);
    assert(x == 42);
    assert(c == '*');
}

  • ^: Reflexionsoperator Produces a reflection value from its operand (^int And ^char,
  • (: refl :): Splicer The reflexive value forms a grammatical element ((:r:) And (:^char:),
  • Reflexionswert The representation of program elements as a constant expression is

Call ^gramOper Creates a reflection with the data type: std::meta::info. std::same_as There is a concept.

It makes no sense to just jump between the areas of grammar and thinking. Here is a more detailed analysis of the program enumString.cpp,

enum => string

The following example converts an enum value to a string:

// enumString.cpp

#include 
#include 
#include 
#include 


template
  requires std::is_enum_v                      // (1)
constexpr std::string enum_to_string(E value) {
  std::string result = "";
  (:expand(std::meta::enumerators_of(^E)):) >>    // (2)
  (&){
    if (value == (:e:)) {
      result = std::meta::identifier_of(e);       // (3)
    }
  };
  return result;
}


int main() {

    std::cout << '\n';

    enum Color { red, green, blue };
    std::cout << "enum_to_string(Color::red): " << enum_to_string(Color::red) << '\n';
    // std::cout << "enum_to_string(42): " << enum_to_string(42) << '\n'; 

    std::cout << '\n';

}

In (1) we use the data type property std::is_enum It was checked whether value There is an enumerator. Expression ^E The reflection value in (2) is generated. The function expand in the same line can be ignored. The extension directive is missing in the current implementation.

Work std::meta::enumerators_of And std::meta::enumerators_of These (2) and (3) are metafunctions. They can only be executed at compile time because they are of the form consteval Are declared.

Here are some meta functions.

namespace std::meta {
  consteval auto members_of(info type_class) -> vector;
  consteval auto bases_of(info type_class) -> vector;

  consteval auto static_data_members_of(info type_class) -> vector;
  consteval auto nonstatic_data_members_of(info type_class) -> vector;

  consteval auto subobjects_of(info type_class) -> vector {
    auto subobjects = bases_of(type_class);
    subobjects.append_range(nonstatic_data_members_of(type_class));
    return subobjects;
  }

  consteval auto enumerators_of(info type_enum) -> vector;
}

All meta functions give a std::vector Reflection provides a number of meta-functions for analyzing data types and generating code.

Using the opposite steps converts the string to an Enum:

template 
  requires std::is_enum_v                           
constexpr std::optional string_to_enum(std::string_view name) {
  template for (constexpr auto e : std::meta::enumerators_of(^E)) {
    if (name == std::meta::identifier_of(e)) {                     
      return (:e:);
    }
  }

  return std::nullopt;
}

Reflection provides several meta functions. I will implement them in my next article.


(RME)

Digital design and UX: lectures needed for the conference in DortmundDigital design and UX: lectures needed for the conference in Dortmund

LEAVE A REPLY

Please enter your comment!
Please enter your name here