C++反射如何实现

Avi*_*ash 4 c++ reflection template-meta-programming

我知道C++不支持反射,但是我通过模板元编程来完成文章Reflection支持,但是不明白这是如何实现的.有没有人会有更多关于如何使用模板元编程在C++中实现这一目标的细节或示例?

Mad*_*ist 5

下面是一个结构的示例,如果类型为Obj的Type具有名为"foo"的Type类型的公共数据成员,则该结构在编译时进行测试.它使用C++ 11功能.虽然可以使用C++ 03功能完成,但我认为这种方法更优越.

首先,我们检查Obj是否是使用std :: is_class的类.如果它不是类,则它不能具有数据成员,因此测试返回false.这是通过下面的部分模板专业化实现的.

我们将使用SFINAE来检测对象是否包含数据成员.我们声明了struct helper,它具有类型为"指向类Obj的类型Type的数据成员的指针"的模板参数.然后我们声明静态函数测试的两个重载版本:第一个,它rsturns指示失败测试的类型通过省略号接受任何参数.请注意,省略号在重载决策中具有最低优先级.第二个返回指示成功的类型,接受带有模板参数&U :: foo的辅助结构的指针.现在我们检查一下使用U绑定到Obj的调用调用返回如果使用nullptr调用并且将typedef调用到testresult.由于最后尝试省略号,编译器首先尝试第二个测试版本.如果helper <&Obj :: foo>是合法类型,只有在Obj具有Type类型的公共数据成员时才会为true,则选择此重载并且testresult将为std :: true_type.如果这不是合法类型,则从可能的候选列表(SFINAE)中排除重载,因此将选择接受任何参数类型的测试的剩余版本,并且testresult将是std :: false_type.最后,将testresult的静态成员值分配给我们的静态成员值,该值指示我们的测试是否成功.

该技术的一个缺点是您需要知道您正在测试的数据成员的名称(在我的示例中为"foo"),因此要为不同的名称执行此操作,您必须编写宏.

您可以编写类似的测试来测试类型是否具有具有特定名称和类型的静态数据成员,如果它具有内部类型或具有特定名称的typedef,如果它具有可以使用某个名称调用的特定名称的成员函数给定的参数类型等等,但现在超出了我的时间范围.

template <typename Obj, typename Type, bool b = std::is_class<Obj>::value>
struct has_public_member_foo
{
  template <typename Type Obj::*> 
  struct helper;

  template <typename U>
  static std::false_type test(...);

  template <typename U>
  static std::true_type test(helper<&U::foo> *);

  typedef decltype(test<Obj>(nullptr)) testresult;

  static const bool value = testresult::value;
};

template <typename Obj, typename Type>
struct has_public_member_foo<Obj, Type, false> : std::false_type { };

struct Foo
{
  double foo;
};

struct Bar
{
  int bar;
};


void stackoverflow() 
{
  static_assert(has_public_member_foo<Foo, double>::value == true, "oops");
  static_assert(has_public_member_foo<Foo, int>::value == false, "oops");
  static_assert(has_public_member_foo<Bar, int>::value == false, "oops");
  static_assert(has_public_member_foo<double, int>::value == false, "oops");
}
Run Code Online (Sandbox Code Playgroud)