11

具体的には、次のような 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 や、関数ポインタ のQualTypeNとFunctionDeclなど見つけるは簡単ですが、問題は、ソース コードを変更せずに、これらの引数を N、F、および F::A に置き換える方法です。F&fopen&fclose

質問は:

  • それが であることをどのように評価F<decltype(&fprintf), &fprintf>::A<N<4>>して知ることができint*ますか?
  • それが であることをどのように評価F<decltype(&fopen), &fopen>::A<N<7>>して知ることができdouble*ますか?
  • 等々...
4

1 に答える 1

5

std::is_same<N<4>, N<4>>::value部分的な解決策があります。唯一の注意点は、戻ることができないということtrueです。constexpr値を直接操作するメソッドを定義するだけでよいので、それで問題ありません。しかし、誰かがこれに対する正しい答えを提供してくれることを願っています。

完全なソリューションと変更された入力をhttps://gist.github.com/4178490に入れました。


引数をクラステンプレートに置き換えてインスタンス化するには、次のようにすることがわかりました。

  1. 引数を使用してClassTemplateDeclClassTemplateSpecializationDeclに変換し、
  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;
}

このメソッドは、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 をスキップしました。それは私の質問の範囲外です。)

于 2012-11-30T20:53:12.867 に答える