将指向成员的指针类型转换为简单指针类型
Converting a pointer-to-member type to a simple pointer type
我有以下类型,我用 decltype
QString UserInfo::*&
我可以通过用 std::remove_reference_t
包装 decltype
来删除 &
部分,但我也想删除 UserInfo::*
部分
我该怎么做才能在我的模板中只使用 QString
类型
我在初始化列表中使用此模板,但我无法访问实体对象或指向 decltype
中的 .*
运算符的指针
你可以写一个trait来从成员函数指针中提取成员的类型:
#include <type_traits>
template <typename T>
struct member_type;
template <typename C, typename T>
struct member_type<T C::*> {
using type = T;
};
template <typename T>
using member_type_t = typename member_type<T>::type;
struct foo {
int bar;
};
int main()
{
int foo::*ptr = &foo::bar;
using T = member_type_t<decltype(ptr)>;
static_assert( std::is_same_v<int,T>);
}
在未计算的上下文中(如 decltype
),没有必要使用有效对象。夸大一点,您甚至可以取消引用其中的空指针,并且不会发生任何坏事,因为实际上从未评估过取消引用。
要创建类型无效但可在未计算的上下文中使用的对象,您可以使用 std::declval
。
template<class T>
using member_type = decltype(std::declval<UserInfo>().*std::declval<T>());
使用模板专业化提取成员类型:
template <typename MemberType>
struct member_type;
template <typename Class, typename Member>
struct member_type<Member Class::*>
{
using type = Member;
};
template<typename T>
using member_type_t = typename member_type<T>::type;
class A
{
public:
int b;
};
using t = member_type_t<decltype(&A::b)>;
这是我使用 C++17 的版本,使用模板时不需要 decltype
(更方便):
#include <iostream>
#include <string>
#include <type_traits>
template <auto Fp>
struct field_type;
template<typename R, typename T, R (T::*FP)>
struct field_type<FP>
{
using type = R;
};
template<typename R, typename T, typename...Args, R (T::*FP)(Args...)>
struct field_type<FP>
{
using type = R;
};
template<auto FP>
using field_type_t = typename field_type<FP>::type;
class Foo {
public:
int x = 0;
double y = 0;
std::string s;
const int cx = 0;
Foo() = default;
void bar() {
std::cout << "bar\n";
}
int par(int z) {
std::cout << "bar\n";
return z;
}
};
template<auto F, typename T>
constexpr bool test = std::is_same_v<field_type_t<F>, T>;
static_assert(test<&Foo::x, int>, "");
static_assert(test<&Foo::cx, const int>, "");
static_assert(test<&Foo::s, std::string>, "");
static_assert(test<&Foo::y, double>, "");
#ifndef HIDE_PROBLEM_ON_GCC_11
static_assert(test<&Foo::bar, void>, "");
static_assert(test<&Foo::par, int>, "");
#endif
由于某些奇怪的原因适用于所有编译器,但不适用于 gcc 11.1 或更新版本。
我有以下类型,我用 decltype
QString UserInfo::*&
我可以通过用 std::remove_reference_t
包装 decltype
来删除 &
部分,但我也想删除 UserInfo::*
部分
我该怎么做才能在我的模板中只使用 QString
类型
我在初始化列表中使用此模板,但我无法访问实体对象或指向 decltype
.*
运算符的指针
你可以写一个trait来从成员函数指针中提取成员的类型:
#include <type_traits>
template <typename T>
struct member_type;
template <typename C, typename T>
struct member_type<T C::*> {
using type = T;
};
template <typename T>
using member_type_t = typename member_type<T>::type;
struct foo {
int bar;
};
int main()
{
int foo::*ptr = &foo::bar;
using T = member_type_t<decltype(ptr)>;
static_assert( std::is_same_v<int,T>);
}
在未计算的上下文中(如 decltype
),没有必要使用有效对象。夸大一点,您甚至可以取消引用其中的空指针,并且不会发生任何坏事,因为实际上从未评估过取消引用。
要创建类型无效但可在未计算的上下文中使用的对象,您可以使用 std::declval
。
template<class T>
using member_type = decltype(std::declval<UserInfo>().*std::declval<T>());
使用模板专业化提取成员类型:
template <typename MemberType>
struct member_type;
template <typename Class, typename Member>
struct member_type<Member Class::*>
{
using type = Member;
};
template<typename T>
using member_type_t = typename member_type<T>::type;
class A
{
public:
int b;
};
using t = member_type_t<decltype(&A::b)>;
这是我使用 C++17 的版本,使用模板时不需要 decltype
(更方便):
#include <iostream>
#include <string>
#include <type_traits>
template <auto Fp>
struct field_type;
template<typename R, typename T, R (T::*FP)>
struct field_type<FP>
{
using type = R;
};
template<typename R, typename T, typename...Args, R (T::*FP)(Args...)>
struct field_type<FP>
{
using type = R;
};
template<auto FP>
using field_type_t = typename field_type<FP>::type;
class Foo {
public:
int x = 0;
double y = 0;
std::string s;
const int cx = 0;
Foo() = default;
void bar() {
std::cout << "bar\n";
}
int par(int z) {
std::cout << "bar\n";
return z;
}
};
template<auto F, typename T>
constexpr bool test = std::is_same_v<field_type_t<F>, T>;
static_assert(test<&Foo::x, int>, "");
static_assert(test<&Foo::cx, const int>, "");
static_assert(test<&Foo::s, std::string>, "");
static_assert(test<&Foo::y, double>, "");
#ifndef HIDE_PROBLEM_ON_GCC_11
static_assert(test<&Foo::bar, void>, "");
static_assert(test<&Foo::par, int>, "");
#endif
由于某些奇怪的原因适用于所有编译器,但不适用于 gcc 11.1 或更新版本。