ken*_*ytm 11 c++ clang abstract-syntax-tree
具体来说,我们有一个像这样的C++源文件:
template <int n>
struct N {};
struct B {
template <typename M>
using A = typename std::conditional<std::is_same<M, N<4>>::value,
int*, void*>::type;
};
template <typename T, T value>
struct F : B {};
template <>
struct F<decltype(&fopen), &fopen> : B {
template <typename M>
using A = double*;
};
template <>
struct F<decltype(&fclose), &fclose> : B {
template <typename M>
using A = typename std::conditional<std::is_same<M, N<16>>::value,
void*, char**>::type;
};
// More specialization of 'F' follows.
Run Code Online (Sandbox Code Playgroud)
这是很容易找到ClassTemplateDecl第N和F,以及QualType和FunctionDecl函数指针&fopen,&fclose等等.但问题是,如何替换这些参数为N,F和F ::一个无需修改源代码.
问题是:
F<decltype(&fprintf), &fprintf>::A<N<4>>并知道它是一个int*?F<decltype(&fopen), &fopen>::A<N<7>>并知道它是一个double*?我有一个部分解决方案,唯一需要注意的是,我无法std::is_same<N<4>, N<4>>::value回归true.好吧,我可以忍受这一点,因为我可以直接定义一个constexpr对值进行操作的方法.但我希望有人可以为此提供正确的答案.
我已将完整的解决方案和修改后的输入放到https://gist.github.com/4178490.
我发现要将参数替换为类模板并实例化它,可以:
方法Sema :: RequireCompleteType间接调用InstantiateClass,并且需要较少的输入,因此我调用此方法.因此,我们会写:
/**
* Instantiate a class template.
*/
ClassTemplateSpecializationDecl* instantiate(ASTContext& ast, Sema& sema,
DeclContext* parent,
ClassTemplateDecl* decl,
ArrayRef<TemplateArgument> args) {
void* ins_point;
auto retval = decl->findSpecialization(args.data(), args.size(), ins_point);
if (retval == nullptr) {
retval = ClassTemplateSpecializationDecl::Create(ast, TTK_Class, parent,
{}, {}, decl,
args.data(), args.size(),
nullptr);
decl->AddSpecialization(retval, ins_point);
}
bool is_incomplete = sema.RequireCompleteType({}, ast.getTypeDeclType(retval),
diag::err_incomplete_type);
return is_incomplete ? nullptr : retval;
}
Run Code Online (Sandbox Code Playgroud)
此方法仅适用于ClassTemplateDecl.在这个问题中我们还有一个TypeAliasTemplateDecl.为此,我将直接调用TemplateDeclInstantiator,因为这是唯一知道TypeAliasTemplateDecl的对象.也许这个方法也适用于ClassTemplateDecl,但我不能确定,因为似乎没有足够的工作单独使用TemplateDeclInstantiator.
/**
* Instantiate a template alias (`template <...> using Foo = ...`).
*/
TypeAliasDecl* instantiate(ASTContext& ast, Sema& sema, DeclContext* parent,
TypeAliasTemplateDecl* decl,
ArrayRef<TemplateArgument> args) {
auto args_count = static_cast<unsigned>(args.size());
TemplateArgumentList arg_list {TemplateArgumentList::OnStack,
args.data(), args_count};
MultiLevelTemplateArgumentList multi_arg_list {arg_list};
TemplateDeclInstantiator instantiator {sema, parent, multi_arg_list};
auto instantiated = instantiator.Visit(decl);
if (auto inst_decl = dyn_cast<TypeAliasTemplateDecl>(instantiated)) {
return inst_decl->getTemplatedDecl();
}
return nullptr;
}
Run Code Online (Sandbox Code Playgroud)
(我跳过了FunctionTemplateDecl,这超出了我的问题的范围.)