我有一个部分解决方案,唯一需要注意的是,我无法std::is_same<N<4>, N<4>>::value
返回true
。好吧,我可以忍受,因为我可以定义一个constexpr
直接对值进行操作的方法。但我希望有人可以为此提供正确的答案。
我已将完整的解决方案和修改后的输入放到https://gist.github.com/4178490中。
我发现要将参数替换为类模板并实例化它,可以:
- 使用参数将ClassTemplateDecl转换为ClassTemplateSpecializationDecl,并且
- 使用Sema::InstantiateClass方法实例化特化。
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;
}
此方法仅适用于 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;
}
(我跳过了 FunctionTemplateDecl,它超出了我的问题范围。)