c++ - libclang 可以解析 CRTP 模式吗?

标签 c++ crtp libclang

我正在尝试使用 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 Base' 没有给出光标,它似乎被忽略了。

有人知道怎么解决吗?

最佳答案

具有 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

所以一个基本的方法是:

  1. 对于每个类(class)
  2. 找到所有具有CXX_BASE_SPECIFIER种类的 child
  3. 对于基本节点,找到所有这些节点都有两个子节点(其中一个是 TEMPLATE_REF 类型)
  4. 对于 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/

相关文章:

c++ - 是否有可能我有一个类的前向声明,而不是在头文件中使它们成为引用或指针

c++ - 可变参数函数 (va_arg) 不适用于 float,而 printf 可以吗?有什么区别?

c++ - 我可以将派生类的模板参数转发到 CRTP 中的基类吗?

c++ - 使用带接口(interface)的 CRTP

python - 获取 lib clang 游标/类型的实际拼写

c++ - 在 opencv imencode 期间调试断言失败

c++ - ID 字段在自定义点类中间歇性丢失

c++ - 实现 CRTP 链表混合 C++

c++ - lib clang.dylib : change installation path

c++ - 使用 Clang 查找特定函数调用的函数定义