跟我学c++高级篇——C++26反射预览

2023-12-16 21:47:36

一、c++23的反射跳票

本来按照预定,c++23中反射就应该比较全的。结果,由于众所周知的原因,线上会议肯定是不如线下会议效率高,那么反射这种对于c++不太急切的功能(当然,也有其它原因)只能向后放一放。只有盼望着下一个版本了,下一个版本就是c++26。不过c++26能否真正上线,还得看最后的结果。

二、c++26的提案

在c++26的提案中,仍然是静态反射为主。主要有下面几个功能:
A、增加反射运算符
一元运算符主要有:

1、…
2^ ::
3^ namespace-name
4^ type-id
5^ cast-expression

需要注意的,提案中只是对一些初级的表达式进行了处理,如果超出范围则反射无法完成。

B、增加拼接器(Splicers)
拼接器是[:…:],其主要的功能如下:

1[: r :] produces an expression evaluating to the entity or constant value represented by r.
2、typename[: r :] produces a simple-type-specifier corresponding to the type represented by r.
3、template[: r :] produces a template-name corresponding to the template represented by r.
4、namespace[: r :] produces a namespace-name corresponding to the namespace represented by r.
5[:r:]:: produces a nested-name-specifier corresponding to the namespace, enumeration type, or class type represented by r.
Attempting to splice a reflection value that does not meet the requirement of the splice (including “invalid reflections”) is ill-formed. For example:

typename[: ^:: :] x = 0;  // Error.

拼接器还有另外一种,即Range拼接器,它主要用来处理元组等的反射。

C、增加了元信息空间
在这个功能里提供了一个命名空间std::meta::info,它主要包括以下的内容:

1、an error (corresponding to an “invalid reflection”)
2any (C++) type and type-alias
3、any function or member function
4、any variable, static data member, or structured binding
5、any non-static data member
6、any constant value
7、any template
8、any namespace

当然,这里面也有不少的限制,这里就不展开,毕竟不是正式的标准。

D、增加元功能(Metafunctions)
主要包括:

1、invalid_reflection, is_invalid, diagnose_error
2、name_of, display_name_of, source_location_of
3、type_of, parent_of, entity_of
4、template_of, template_arguments_of
5、members_of, nonstatic_data_members_of, bases_of, enumerators_of, subobjects_of
6、substitute
7、entity_ref<T>, value_of<T>, ptr_to_member<T>
8、test_type<Pred>
9、 Other Singular Reflection Predicates
10、reflect_value
11、nsdm_description, synth_struct, synth_union
12、Data Layout Reflection

这里面的细节不是太好说清楚,大家可以去看相关的提案:
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2996r0.html#ref-P2670R1
省得误导大家。

三、相关的例程

1、类型和值之间的反射转换

constexpr auto r = ^int;
typename[:r:] x = 42;       // Same as: int x = 42;
typename[:^char:] c = '*';  // Same as: char c = '*';

2、成员反射

struct S { unsigned i:2, j:6; };

consteval auto member_number(int n) {
  if (n == 0) return ^S::i;
  else if (n == 1) return ^S::j;
  else return std::meta::invalid_reflection("Only field numbers 0 and 1 permitted");
}

int main() {
  S s{0, 0};
  s.[:member_number(1):] = 42;  // Same as: s.j = 42;
  s.[:member_number(5):] = 0;   // Error (likely with "Only field numbers 0 and 1 permitted" in text).
}

3、类型和大小的列表反射

//sizes将是一个std::array<std::size_t, 3>初始化为{sizeof(int), sizeof(float), sizeof(double)}
constexpr std::array types = {^int, ^float, ^double};
constexpr std::array sizes = []{
  std::array<std::size_t, types.size()> r;
  std::ranges::transform(types, r.begin(), std::meta::size_of);
  return r;
}();

//产生相同的数组sizes
template<class...> struct list {};

using types = list<int, float, double>;

constexpr auto sizes = []<template<class...> class L, class... T>(L<T...>) {
    return std::array<std::size_t, sizeof...(T)>{{ sizeof(T)... }};
}(types{});

4、执行make_integer_sequence

#include <utility>
#include <vector>

template<typename T>
consteval std::meta::info make_integer_seq_refl(T N) {
  std::vector args{^T};
  for (T k = 0; k < N; ++k) {
    args.push_back(std::meta::reflect_value(k));
  }
  return substitute(^std::integer_sequence, args);
}

template<typename T, T N>
  using make_integer_sequence = [:make_integer_seq_refl<T>(N):];

5、反射枚举

//正向
template <typename E>
  requires std::is_enum_v<E>
constexpr std::string enum_to_string(E value) {
  template for (constexpr auto e : std::meta::members_of(^E)) {
    if (value == [:e:]) {
      return std::string(std::meta::name_of(e));
    }
  }

  return "<unnamed>";
}

enum Color { red, green, blue };
static_assert(enum_to_string(Color::red) == "red");
static_assert(enum_to_string(Color(42)) == "<unnamed>");
//反向
template <typename E>
  requires std::is_enum_v<E>
constexpr std::optional<E> string_to_enum(std::string_view name) {
  template for (constexpr auto e : std::meta::members_of(^E)) {
    if (name == std::meta::name_of(e)) {
      return [:e:];
    }
  }

  return std::nullopt;
}

6、结构体数组的反射

struct point {
  float x;
  float y;
  float z;
};

using points = struct_of_arrays<point, 30>;
// equivalent to:
// struct points {
//   std::array<float, 30> x;
//   std::array<float, 30> y;
//   std::array<float, 30> z;
// };

其它还有几种,在这里不再一一列举。

四、总结

看了c++26中的提案,可以发现其实很多现在的反射框架的轮子基本都可以废弃了。不过,能把反射最终支持,估计得2028年左右了,时间还有的是。喜欢造轮子的同学可以继续造,反正在造轮子的过程中,可以更好的学习反射的原理和实践,同样能更好的理解新标准中的反射。这样,在未来的应用中,也会更加轻松的引入标准库内的反射。
在后面反射实现分析讲解中,基本也会沿着大致相同的路线进行。

文章来源:https://blog.csdn.net/fpcc/article/details/135037576
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。