2012-11-18 11 views
11

Konkretnie mamy C++ pliku źródłowego takiego:Jak przeprowadzić podstawianie szablonów w bibliotece klang?

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. 

Łatwo jest znaleźć ClassTemplateDecl s o N i F oraz QualType i FunctionDecl ze wskaźników funkcji &fopen, &fclose, itd. Ale Problem polega na tym, jak zastąpić te argumenty N, F i F :: A bez modyfikowania kodu źródłowego.

Pytanie brzmi:

  • Jak mogę ocenić F<decltype(&fprintf), &fprintf>::A<N<4>> i wiem, że jest to int*?
  • Jak ocenić F<decltype(&fopen), &fopen>::A<N<7>> i wiem, że jest to double*?
  • i tak dalej ...
+0

nie jestem całkowicie pewien, czy rozumiem, co chce zrobić, ale dlaczego nie można użyć typeid? –

+0

@AndreiTita: Próbujemy to ocenić za pomocą parsera C++ (clang). – kennytm

Odpowiedz

5

Mam częściowe rozwiązanie, jedynym zastrzeżeniem jest to, że nie mogę dostać std::is_same<N<4>, N<4>>::value wrócić true. Cóż, mogę z tym żyć, ponieważ mogłem zdefiniować metodę, która działa bezpośrednio na wartości. Mam jednak nadzieję, że ktoś mógłby udzielić na to poprawnej odpowiedzi.

Położyłem kompletne rozwiązanie i zmodyfikowane dane wejściowe na https://gist.github.com/4178490.


odkryłem, że aby zastąpić argumenty do szablonu klasy i oznacz ją, można by:

  1. używać argumentów, aby włączyć ClassTemplateDecl do ClassTemplateSpecializationDecl i
  2. instancję specjalizacja korzystania Metoda Sema::InstantiateClass.

Metoda Sema::RequireCompleteType pośrednio wywołuje InstantiateClass i wymaga mniejszej ilości danych wejściowych, więc nazywam tę metodę zamiast tego. Dlatego chcielibyśmy napisać:

/** 
* 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; 
} 

Ta metoda działa tylko dla ClassTemplateDecl. W pytaniu mamy także TypeAliasTemplateDecl. W tym celu zamierzam bezpośrednio wywołać obiekt TemplateDeclInstantiator, ponieważ jest to jedyny obiekt, który zna TypeAliasTemplateDecl. Być może ta metoda działa również z ClassTemplateDecl, ale nie mogę być pewny, ponieważ wydaje się, że za mało pracy odbywa się za pomocą samego 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; 
} 

(pominąłem FunctionTemplateDecl, to jest poza zakresem mojego pytania.)

Powiązane problemy