2017-11-01 15 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

예 I가 필요 : 물론

using ret_type = std::conditional_t< std::is_function_v<T>, std::invoke_result_t<T C::*, C>, T>; 

당신이 좌우 스텝에게조차 할 수 있도록 decltype를,이, C++ 17 ret_type의 std :: conditional_t ​​버전을 사용하십시오. std :: invoke_result_t에서 모든 어려운 일이 일어나고 있다고 가정합니다. 코드는 const 멤버 함수에서도 작동합니다. 마지막으로, 이제 Foo에서 키를 추출하는 메소드를 작성하려고하므로 decltype을 단계별로 스테핑하는 것이 정확하게 수행하고 싶습니다. –

+0

초보자에서 메타 프로그래밍에 이르기까지 필자가 몰랐던 패턴은 템플릿 형질 특성 클래스를 선언 한 다음 멤버 유형 및 클래스 유형에 템플릿을 사용하여 멤버에 대한 포인터에 대한 특성의 특성을 정의하는 것이 었습니다. 인덱스 별칭 템플릿을 인스턴스화하는 동안 C++ 17은 구성원에 대한 포인터를 개별 조각으로 확장하는 특성 서식 파일과 일치하는 항목을 찾습니다. –