2012-11-18 8 views
11

は具体的に、我々はこのようなC++のソースファイルを持っている: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. 

NF、およびQualTypeと関数ポインタ&fopenFunctionDecl&fclose、などしかし、のClassTemplateDecl sのを見つけるのは簡単です問題は、これらの引数をソースコードを変更せずにN、F、F :: Aに代入する方法です。

質問です:

  • 私はF<decltype(&fprintf), &fprintf>::A<N<4>>を評価し、それがint*であることを知ってどうすればよいですか?
  • F<decltype(&fopen), &fopen>::A<N<7>>をどのように評価し、double*であることがわかりますか?私は部分的な解決策を持っている
  • のように...
+0

私は私はあなたがやろうとしているのか理解全くわからないが、なぜあなたはタイプIDを使用することはできませんか? –

+0

@AndreiTita:これをC++パーサー(clang)で評価しようとしています。 – kennytm

答えて

5

、唯一の注意点は、私はstd::is_same<N<4>, N<4>>::valuetrueを返すために得ることができない、ということです。私はちょうど値に直接作用するconstexprメソッドを定義することができるので、私はそれで生きることができます。しかし、私は誰かがこれに対して正しい答えを提供できることを願っています。

私は完全な解決策と修正された入力をhttps://gist.github.com/4178490に入れました。

  1. 使用して、引数がClassTemplateSpecializationDeclClassTemplateDeclをオンにすると、
  2. インスタンス化の専門は、使用して:


    私は1つは、それはそれをクラステンプレートに引数を代用してインスタンス化するだろうことがわかりました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もあります。このため、これはTypeAliasTemplateDeclを知る唯一のオブジェクトなので、TemplateDeclInstantiatorを直接呼び出します。おそらくこのメソッドは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をスキップする。)

関連する問題