将指向成员的指针类型转换为简单指针类型

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 或更新版本。

https://godbolt.org/z/4e7oKbod1