2012-11-18 12 views
11

विशेष रूप से, हम इस तरह एक सी ++ स्रोत फ़ाइल है:क्लैंग लाइब्रेरी में टेम्पलेट प्रतिस्थापन कैसे करें?

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 और F, और QualType और समारोह संकेत &fopen की FunctionDecl, &fclose, आदि लेकिन ClassTemplateDecl रों को खोजने के लिए आसान है समस्या यह है कि इन तर्कों को एन, एफ और एफ :: ए में स्रोत कोड को संशोधित किए बिना कैसे बदला जाए।

सवाल यह है:

  • मैं F<decltype(&fprintf), &fprintf>::A<N<4>> कैसे मूल्यांकन और पता है कि यह एक int* है?
  • मैं F<decltype(&fopen), &fopen>::A<N<7>> का मूल्यांकन कैसे करूं और जान सकता हूं कि यह double* है?
  • और इतने पर ...
+0

मैं कर रहा हूँ नहीं पूरी तरह से यकीन है कि मैं समझता हूँ कि तुम क्या करने कोशिश कर रहे हैं, लेकिन क्यों आप typeid उपयोग नहीं कर सकते? –

+0

@AndreiTita: हम इसे सी ++ पार्सर (क्लैंग) के साथ मूल्यांकन करने का प्रयास कर रहे हैं। – kennytm

उत्तर

5

मैं एक आंशिक समाधान मिल गया है, केवल चेतावनी है कि, मैं std::is_same<N<4>, N<4>>::value नहीं मिल सकता है true वापस जाने के लिए है। खैर मैं इसके साथ रह सकता हूं, क्योंकि मैं सिर्फ constexpr विधि को परिभाषित कर सकता हूं जो सीधे मानों पर चलती है। लेकिन मुझे आशा है कि कोई इसके लिए सही उत्तर दे सकता है।

मैंने पूरा समाधान और संशोधित इनपुट https://gist.github.com/4178490 पर रखा है।


मैं होता पाया है कि एक वर्ग टेम्पलेट में तर्क स्थानापन्न और यह दृष्टांत के लिए, एक:

  1. उपयोग तर्क ClassTemplateSpecializationDecl में ClassTemplateDecl चालू करने के लिए, और
  2. का दृष्टांत विशेषज्ञता का उपयोग कर 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; 
} 

यह विधि केवल क्लास टेम्पलेट डीक्ल के लिए काम करती है। प्रश्न में हमारे पास TypeAliasTemplateDecl भी है। इसके लिए, मैं सीधे TemplateDeclInstantiator का आह्वान करने जा रहा हूं, क्योंकि यह एकमात्र वस्तु है जो TypeAliasTemplateDecl को जानता है। शायद यह विधि ClassTemplateDecl के साथ भी काम करती है, लेकिन मुझे यकीन नहीं है क्योंकि ऐसा लगता है कि अकेले टेम्पलेट डीक्लिंस्टेंटिएटर का उपयोग करके पर्याप्त काम नहीं किया जाता है।

/** 
* 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 को छोड़ दिया है, यह मेरे सवाल के दायरे से बाहर है।)