我正在尝试使用libclang解析C++,但CRTP模式似乎有问题,即当类从用派生类实例化的模板继承时:

// The Curiously Recurring Template Pattern (CRTP)
template<class T>
class Base
{
  // methods within Base can use template to access members of Derived
};

class Derived : public Base<Derived>
{
  // ...
};

我希望libclang找到游标类型CXCursor_CXXBaseSpecifier,但是它只给了我CXCursor_ClassDecl类型。

如果Base不是模板类,则libclang将找到CXCursor_CXXBaseSpecifier。

我要完成的工作是找到从Base继承的类,但是当libclang仅给出ClassDecl类型时是不可能的。 “公共(public)基础”没有给出光标,它似乎被忽略了。

有谁知道如何解决这个问题?

最佳答案

具有CXX_BASE_SPECIFIER的游标将具有子游标,使您可以确定此信息。在基本说明符引用模板类的情况下,它将有两个子节点(种类)TEMPLATE_REF和TYPE_REF。您可以在TEMPLATE_REF节点中使用该信息来与类模板游标进行比较。

为了更清楚一点,我将举一个小例子。漂亮地打印以下AST的(libclang)版本:

template<class T>
class Base { };
class X1 : public Base<X1> {};
class Y1 {};
class X2 : public Y1 {};

给出:
TRANSLATION_UNIT tmp.cpp
  +--CLASS_TEMPLATE Base
  |  +--TEMPLATE_TYPE_PARAMETER T
  +--CLASS_DECL X1
  |  +--CXX_BASE_SPECIFIER Base<class X1>
  |     +--TEMPLATE_REF Base
  |     +--TYPE_REF class X1
  +--CLASS_DECL Y1
  +--CLASS_DECL X2
     +--CXX_BASE_SPECIFIER class Y1
        +--TYPE_REF class Y1

因此,一种基本方法是:
  • 对于每个类
  • 查找所有具有CXX_BASE_SPECIFIER种类
  • 的 child
  • 对于基本节点,找到所有具有两个子节点的节点(其中一个具有TEMPLATE_REF的种类)
  • 对于TEMPLATE_REF节点,检查它们是否与目标类模板具有相同的定义。

  • 鉴于这将是C / C++中非常大的代码段(用于stackoverflow),我将介绍实现这些步骤的Python 2版本,这应该很容易翻译。
    import clang
    from clang.cindex import CursorKind
    
    
    def find_template_class(name):
        for c in tu.cursor.walk_preorder():
            if (c.kind == CursorKind.CLASS_TEMPLATE) and (c.spelling == name):
                return c
    
    def inherits_from_template_class(node, base):
        for c in node.get_children():
            if c.kind != CursorKind.CXX_BASE_SPECIFIER:
                continue
            children = list(c.get_children())
            if len(children) != 2:
                continue
            if children[0].kind != CursorKind.TEMPLATE_REF:
                continue
            ctd = children[0].get_definition()
            if ctd == base:
                return True
        return False
    
    idx = clang.cindex.Index.create()
    tu = idx.parse('tmp.cpp', unsaved_files=[('tmp.cpp', s)],  args='-xc++'.split())
    base = find_template_class('Base')
    for c in tu.cursor.walk_preorder():
        if CursorKind.CLASS_DECL != c.kind:
            continue
        if inherits_from_template_class(c, base):
            print c.spelling
    

    关于c++ - libclang可以解析CRTP模式吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42795408/

    10-08 21:10