如何使用类模板特化创建别名模板的特化?

时间:2017-11-01 17:25:47

标签: c++ c++17 template-specialization

我一直在玩指向数据成员和指向成员函数的指针,我正在尝试创建一个模板,该模板将使用类类型和函数的返回类型或类型来创建专用的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 个答案:

答案 0 :(得分:2)

我想你可能只想:

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始终是引用类型。所以你可能想做类似的事情:

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

当然,这是C ++ 17,所以你甚至可以左右步骤:

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>