Как выполнить замену шаблона в библиотеке clang?

В частности, у нас есть исходный файл 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.

Это легко найти ClassTemplateDeclс N а также Fи QualType а также FunctionDecl указателей функций &fopen, &fcloseи т. д. Но проблема в том, как подставить эти аргументы в N, F и F :: A без изменения исходного кода.

Вопрос в том:

  • Как я оцениваю F<decltype(&fprintf), &fprintf>::A<N<4>> и знаю, что это int*?
  • Как я оцениваю F<decltype(&fopen), &fopen>::A<N<7>> и знаю, что это double*?
  • и так далее…

11

Решение

У меня есть частичное решение, единственное предостережение в том, что я не могу получить std::is_same<N<4>, N<4>>::value возвращать true, Ну, я могу жить с этим, как я мог бы просто определить constexpr метод, который действует на значения непосредственно. Но я надеюсь, что кто-то может дать правильный ответ на это.

Я поставил полное решение и измененный ввод в https://gist.github.com/4178490.


Я обнаружил, что для подстановки аргументов в шаблон класса и создания его экземпляра нужно:

  1. Используйте аргументы, чтобы включить ClassTemplateDecl в ClassTemplateSpecializationDecl, а также
  2. Определить специализацию, используя Сема :: InstantiateClass метод.

Метод Сема :: 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, это выходит за рамки моего вопроса.)

5

Другие решения

Других решений пока нет …