如何使用 class 模板专业化创建别名模板的专业化?
How do I create specializations of alias templates using class template specialization?
我一直在研究指向数据成员的指针和指向成员函数的指针,我正在尝试创建一个模板,该模板将使用 class 类型和 return函数类型或数据成员类型。
所以:
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 组合成一个模板别名,例如IndexOnMember 指针。我很欣赏只有函数和 class 模板允许专业化。到目前为止,我所有的尝试都失败了。
作为后续,我还希望能够支持从指向 const 成员函数的指针计算出类型。
我想你可能只想:
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,所以你甚至可以避开 decltype:
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>
我一直在研究指向数据成员的指针和指向成员函数的指针,我正在尝试创建一个模板,该模板将使用 class 类型和 return函数类型或数据成员类型。
所以:
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 组合成一个模板别名,例如IndexOnMember 指针。我很欣赏只有函数和 class 模板允许专业化。到目前为止,我所有的尝试都失败了。
作为后续,我还希望能够支持从指向 const 成员函数的指针计算出类型。
我想你可能只想:
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,所以你甚至可以避开 decltype:
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>