我如何将反射添加到C ++应用程序?

我希望能够反省一个C ++类的名称,内容(即成员和他们的类型)等。我在这里讲的是本地C ++,而不是托管C ++,它有反思。 我意识到C ++使用RTTI提供一些有限的信息。 哪些额外的库(或其他技术)可以提供这些信息?


你需要做的是让预处理器产生关于这些字段的反射数据。 这些数据可以存储为嵌套类。

首先,为了使它更容易和更干净地写入预处理器,我们将使用类型化表达式。 类型化表达式就是将该类型放在括号中的表达式。 所以,而不是写int x你会写(int) x 。 这里有一些方便的宏来帮助键入表达式:

#define REM(...) __VA_ARGS__
#define EAT(...)

// Retrieve the type
#define TYPEOF(x) DETAIL_TYPEOF(DETAIL_TYPEOF_PROBE x,)
#define DETAIL_TYPEOF(...) DETAIL_TYPEOF_HEAD(__VA_ARGS__)
#define DETAIL_TYPEOF_HEAD(x, ...) REM x
#define DETAIL_TYPEOF_PROBE(...) (__VA_ARGS__),
// Strip off the type
#define STRIP(x) EAT x
// Show the type without parenthesis
#define PAIR(x) REM x

接下来,我们定义一个REFLECTABLE宏来生成关于每个字段的数据(加上字段本身)。 这个宏将被这样调用:

REFLECTABLE
(
    (const char *) name,
    (int) age
)

所以使用Boost.PP我们遍历每个参数并生成如下所示的数据:

// A helper metafunction for adding const to a type
template<class M, class T>
struct make_const
{
    typedef T type;
};

template<class M, class T>
struct make_const<const M, T>
{
    typedef typename boost::add_const<T>::type type;
};


#define REFLECTABLE(...) 
static const int fields_n = BOOST_PP_VARIADIC_SIZE(__VA_ARGS__); 
friend struct reflector; 
template<int N, class Self> 
struct field_data {}; 
BOOST_PP_SEQ_FOR_EACH_I(REFLECT_EACH, data, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))

#define REFLECT_EACH(r, data, i, x) 
PAIR(x); 
template<class Self> 
struct field_data<i, Self> 
{ 
    Self & self; 
    field_data(Self & self) : self(self) {} 
    
    typename make_const<Self, TYPEOF(x)>::type & get() 
    { 
        return self.STRIP(x); 
    }
    typename boost::add_const<TYPEOF(x)>::type & get() const 
    { 
        return self.STRIP(x); 
    }
    const char * name() const 
    {
        return BOOST_PP_STRINGIZE(STRIP(x)); 
    } 
}; 

它所做的是生成一个常量fields_n ,它是类中可反映字段的数量。 然后专门为每个领域的field_data 。 它也是reflector类的朋友,所以即使它们是私人的,它也可以访问这些字段:

struct reflector
{
    //Get field_data at index N
    template<int N, class T>
    static typename T::template field_data<N, T> get_field_data(T& x)
    {
        return typename T::template field_data<N, T>(x);
    }

    // Get the number of fields
    template<class T>
    struct fields
    {
        static const int n = T::fields_n;
    };
};

现在遍历我们使用访问者模式的字段。 我们创建一个从0到字段数的MPL范围,并访问该索引处的字段数据。 然后它将现场数据传递给用户提供的访问者:

struct field_visitor
{
    template<class C, class Visitor, class I>
    void operator()(C& c, Visitor v, I)
    {
        v(reflector::get_field_data<I::value>(c));
    }
};


template<class C, class Visitor>
void visit_each(C & c, Visitor v)
{
    typedef boost::mpl::range_c<int,0,reflector::fields<C>::n> range;
    boost::mpl::for_each<range>(boost::bind<void>(field_visitor(), boost::ref(c), v, _1));
}

现在,我们把这一切放在一起。 以下是我们如何定义可反映的Person类:

struct Person
{
    Person(const char *name, int age)
        :
        name(name),
        age(age)
    {
    }
private:
    REFLECTABLE
    (
        (const char *) name,
        (int) age
    )
};

以下是使用反射数据遍历字段的广义print_fields函数:

struct print_visitor
{
    template<class FieldData>
    void operator()(FieldData f)
    {
        std::cout << f.name() << "=" << f.get() << std::endl;
    }
};

template<class T>
void print_fields(T & x)
{
    visit_each(x, print_visitor());
}

使用具有可反射Person类的print_fields的示例:

int main()
{
    Person p("Tom", 82);
    print_fields(p);
    return 0;
}

哪些输出:

name=Tom
age=82

瞧,我们刚刚在C ++中用100行代码实现了反射。


游泳有两种reflection

  • 通过遍历一个类型的成员来检查,枚举它的方法等等。

    这对于C ++来说是不可能的。
  • 通过检查类类型(类,结构体,联合体)是否具有方法或嵌套类型来检查是否来自另一特定类型。

    C ++使用template-tricks 。 使用boost::type_traits很多事情(比如检查一个类型是否是整数)。 为了检查成员函数的存在,使用是否可以编写一个模板来检查函数的存在? 。 为了检查某个嵌套类型是否存在,使用普通的SFINAE。
  • 如果你正在寻找方法来完成1),比如查看一个类有多少种方法,或者像获取类ID的字符串表示那样,恐怕没有标准C ++方法来做到这一点。 你必须使用其中之一

  • 像Meta编译器这样的Qt元对象编译器,可以将您的代码转换为额外的元信息。
  • 一个框架宏的宏,允许您添加所需的元信息。 你需要告诉框架所有的方法,类名,基类和它需要的一切。
  • C ++的编译速度很快。 如果你想要像C#或Java那样的高级检查,那么恐怕我必须告诉你,没有一些努力就没有办法。


    我会喜欢一匹小马,但小马不是免费的。 :-P

    http://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI就是你将要得到的。 像你正在思考的反射 - 在运行时可用的完全描述性元数据 - 默认情况下C ++不存在。

    链接地址: http://www.djcxy.com/p/47639.html

    上一篇: How can I add reflection to a C++ application?

    下一篇: Reflection support in C