2012-11-18 24 views
11

Cụ thể, chúng tôi có một C++ nguồn tập tin như thế này:Làm thế nào để thực hiện thay thế mẫu trong thư viện clang?

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. 

Nó rất dễ dàng để tìm ra ClassTemplateDecl s của NF, và QualTypeFunctionDecl của con trỏ hàm &fopen, &fclose, vv Tuy nhiên, các vấn đề là làm thế nào để thay thế các đối số này vào N, F và F :: A mà không sửa đổi mã nguồn.

Câu hỏi đặt ra là:

  • Làm thế nào để đánh giá F<decltype(&fprintf), &fprintf>::A<N<4>> và biết rằng nó là một int*?
  • Làm cách nào để đánh giá F<decltype(&fopen), &fopen>::A<N<7>> và biết rằng đó là double*?
  • và vân vân ...
+0

Tôi không hoàn toàn chắc chắn tôi hiểu những gì bạn đang cố gắng để làm, nhưng tại sao bạn không thể sử dụng typeid? –

+0

@AndreiTita: Chúng tôi đang cố gắng đánh giá điều này bằng trình phân tích cú pháp C++ (clang). – kennytm

Trả lời

5

Tôi đã có một giải pháp một phần, caveat duy nhất là, tôi không thể nhận std::is_same<N<4>, N<4>>::value trở true. Tôi cũng có thể sống với điều đó, vì tôi chỉ có thể xác định phương thức constexpr hoạt động trên các giá trị trực tiếp. Nhưng tôi hy vọng ai đó có thể cung cấp một câu trả lời đúng cho việc này.

Tôi đã đặt giải pháp hoàn chỉnh và đầu vào được sửa đổi cho https://gist.github.com/4178490.


Tôi đã phát hiện ra rằng để thay đối số vào một lớp học mẫu và nhanh chóng nó, người ta sẽ:

  1. Sử dụng các đối số để biến ClassTemplateDecl vào ClassTemplateSpecializationDecl, và
  2. nhanh chóng chuyên môn sử dụng Sema::InstantiateClass phương pháp.

Phương thức Sema::RequireCompleteType gián tiếp gọi InstantiateClass và yêu cầu ít đầu vào hơn, vì vậy tôi gọi phương thức này thay thế. Do đó, chúng tôi sẽ viết:

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

Phương pháp này chỉ hoạt động đối với ClassTemplateDecl. Trong câu hỏi, chúng tôi cũng có một số TypeAliasTemplateDecl. Đối với điều này, tôi sẽ gọi trực tiếp số TemplateDeclInstantiator vì đây là đối tượng duy nhất biết TypeAliasTemplateDecl. Có lẽ phương pháp này cũng làm việc với ClassTemplateDecl, nhưng tôi không thể chắc chắn vì nó có vẻ không đủ công việc được thực hiện bằng cách sử dụng TemplateDeclInstantiator một mình.

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

(tôi bỏ qua FunctionTemplateDecl, nó được ra khỏi phạm vi của câu hỏi của tôi.)

Các vấn đề liên quan