2017-11-01 3 views
2

私は、データメンバへのポインタとメンバ関数へのポインタで遊んでいました。クラスの型と関数の戻り値の型または関数の型を使用して特殊なstd :: mapを作成するテンプレートを作成しようとしています。データメンバー。クラステンプレートの特殊化を使用してエイリアステンプレートのスペシャライゼーションを作成するにはどうすればよいですか?

だから:

template<typename PMember> 
using Index = std::map<typename return_type_of<PMember>, typename pod_type_of<PMember>>; 

struct Foo { int x; char* get_name(); }; 
Index<decltype(&Foo::x)> indexOnX; // std::map<int, Foo> 
Index<decltype(&Foo::get_name)> indexOnGetName; // std::map<char*, Foo> 

私はそれを行う2つのエイリアステンプレートを記述するために管理しているが、悲しいことに、彼らは別の名前を持っています。 Code in Godbolt:私が望む何

include <type_traits> 
#include <map> 

/** 
* Splits a pointer to member function type into it's class and return type. 
* This only works with member functions that take no arguments. 
*/ 
template <typename MemFunc_t> 
struct decompose_member_function_pointer { 
    // We hide the implementation within the details struct. These should not be used by users of the class. 
    struct details { 
    // This templated function will be used to split M into it's component parts. 
    template <typename C, typename T> 
    static T get_returntype(T (C::*v)()); 

    template <typename C, typename T> 
    static C get_classtype(T (C::*v)()); 
    }; 

    using return_type = decltype(details::get_returntype(std::declval<std::decay_t<MemFunc_t>>())); 
    using type = decltype(details::get_classtype(std::declval<std::decay_t<MemFunc_t>>())); 
}; 

template <typename Member_t> 
using decompose_member_function_pointer_t = typename decompose_member_function_pointer<Member_t>::type; 
template <typename Member_t> 
using decompose_member_function_pointer_rt = typename decompose_member_function_pointer<Member_t>::return_type; 

template <typename Member_t> 
struct decompose_member_object_pointer { 
    struct details { 
    template <typename C, typename T> 
    static T get_returntype(T C::*v); 

    template <typename C, typename T> 
    static C get_classtype(T C::*v); 
    }; 

    using return_type = decltype(details::get_returntype(std::declval<Member_t>())); 
    using type = decltype(details::get_classtype(std::declval<Member_t>())); 
}; 

template <typename Member_t> 
using decompose_member_object_pointer_t = typename decompose_member_object_pointer<Member_t>::type; 
template <typename Member_t> 
using decompose_member_object_pointer_rt = typename decompose_member_object_pointer<Member_t>::return_type; 


template<typename MemFunc, typename = std::enable_if_t<std::is_member_function_pointer_v<MemFunc>>> 
using IndexOnMFP = std::map< 
    decompose_member_function_pointer_rt<MemFunc>, 
    decompose_member_function_pointer_t<MemFunc>>; 

template<typename MemFunc, typename = std::enable_if_t<std::is_member_object_pointer_v<MemFunc>>> 
using IndexOnMOP = std::map< 
    decompose_member_object_pointer_rt<MemFunc>, 
    decompose_member_object_pointer_t<MemFunc>>; 


// Now try using these alias templates 
struct MyClass 
{ 
    char value; 
    int age(); 
    int age2() const; 
}; 

IndexOnMOP<decltype(&MyClass::value)> indexOnValue; 
IndexOnMFP<decltype(&MyClass::age)> indexOnAge; 

は、例えば、単一のテンプレート・エイリアスにIndexOnMOPとIndexOnMFPを組み合わせることができるようにすることですIndexOnMemberPointer。私は関数とクラステンプレートだけが特殊化を可能にすることに感謝します。今までの私の試みはすべて失敗しました。

また、ポインタからconstメンバ関数への型の作業をサポートすることもできます。

答えて

1

私はあなただけしたいかもしれないと思う:

template <class > 
struct trait; 

template <class C, class T> 
struct trait<T C::*> { 
    using class_type = C; 
    using ret_type = std::invoke_result_t<T C::*, C>; 
}; 

template <typename PMember, typename T = trait<PMember>> 
using Index = std::map<typename T::ret_type, typename T::class_type>; 

これは、会員データへのメンバ関数とポインタへのポインタの両方のために動作します。ただし、ret_typeは常に参照タイプなので、メンバーデータには注意が必要です。

template <auto PMember, typename T = trait<decltype(PMember)>> 
using Index = std::map<typename T::ret_type, typename T::class_type>; 

Index<&Foo::x>  indexOnX;  // std::map<int, Foo> 
Index<&Foo::get_name> indexOnGetName; // std::map<char*, Foo> 
+0

はい、私は必要な:だからあなたのような何かをすることもできます。あなたもサイドステップdecltypeことができるように

もちろん
using ret_type = std::conditional_t< std::is_function_v<T>, std::invoke_result_t<T C::*, C>, T>; 

を、これは、C++ 17でありますret_typeのstd :: conditional_tバージョンを使用してください。私はstd :: invoke_result_tですべての困難が起きていると推測しています。これは、コードがconstメンバー関数でも動作するためです。 最後に、Fooからキーを抽出するメソッドを記述したいので、decltypeをサイドステッピングしています。 –

+0

初心者からテンプレートのメタプログラミングでは、私が知らなかったパターンは、テンプレート化された形質クラスを宣言し、メンバへのポインタのための特性の特化を定義し、メンバの型とクラスの型にテンプレート化しました。 Indexエイリアステンプレートをインスタンス化している間、C++ 17はメンバへのポインタを個々の部分に展開する特性テンプレートに一致するものを見つけます。 –

関連する問題