获取成员指针所指向的成员类型

4

我希望提取成员指针所指向的成员类型。

template<someType myClass::*member>
void demo(myClass& instance, void* ptr) {
    instance.*member = *reinterpret_cast<someType*>(ptr);  // can the someType in this line be deduced from member?
}

我尝试使用评论中建议的decltype,但是我遇到了一些问题:

instance.*member= static_cast<decltype(instance.*member)>((*buffer)[offset]);

buffer 是一个 std::shared_ptr<std::vector<uint8_t>>
someTypeuint32_t

我得到以下错误信息:

error: invalid static_cast from type ‘__gnu_cxx::__alloc_traits >::value_type {aka unsigned char}’ to type ‘uint32_t& {aka unsigned int&}’

据我了解,使用 member 定义为 uint32_t instance::*memberdecltype(instance.*member) 会产生一个引用 uint32_t& 而不是 uint32_t。我尝试通过传值的方式来传递实例,但是错误仍然存在。我知道 std::remove_reference,但是我不明白为什么引用会首先出现。

如果我能够在没有类实例的情况下提取 someType,那将是进一步的改进。然而,我不知道如何实现这一点,虽然通过使用 std lib,我可以获得没有指针的类:

template <T*>
struct removePointer {
  typedef T type;
}

我不知道如何以一种能获取类的someType部分的形式编写代码,而不需要事先知道这个类。我可以编写以下内容,但仍然需要显式传递类名和类型名称,是否有一种自动提取它们的方法?此外,以下代码根本无法编译(http://ideone.com/8VlKO4):

#include <iostream>
using namespace std;

template <class C,typename T, T C::*v>
struct getPointerType {
typedef T type;
};

class Test {
int value;
};

int main() {
int Test::*member=nullptr;
cout << typeid(getPointerType<Test, int, decltype(member)>::type) << std::endl;
return 0;
}

在C++11中,您可以使用decltype()来显式推断所需的类型。如果您没有启用C++11,则可以使用typeof/__typeof__ - oakad
@oakad,你能帮我解决decltype的问题吗?我更新了问题以显示我在使用decltype时遇到的问题,并添加了有关使用模板的建议,但我担心使用模板的想法行不通。 - ted
这个回答解决了你的问题吗?从成员变量指针获取类和成员类型 - Artyer
2个回答

4

说实话,我有点难以理解你想要实现什么,所以我会专注于更新的部分。

显然,你不能将派生自 decltype 的类型作为值参数传递给模板。此外,你不能将非 constexpr 值作为模板参数传递(因此你不能只是将 member 变量插入模板参数并期望它能编译通过)。

但是,你可以依赖编译器能够推导出正确的函数调用来处理非 costexpr 变量:

template <class C, typename T>
T getPointerType(T C::*v);

class Test {
    int value;
};

int main() {
    int Test::*member=nullptr;
    cout << typeid(decltype(member)).name() << std::endl;
    cout << typeid(decltype(getPointerType(member))).name() << std::endl;
    return 0;
}

上面的代码将输出:
M4Testi //int Test::*
i       //int

当然,我们可以更加“滥用”模板替换功能:

template <typename M>
struct getPointerType {
   template <typename C, typename T>
   static T get_type(T C::*v);

   typedef decltype(get_type(static_cast<M>(nullptr))) type;
};

class Test {
    int value;
};

int main() {
    int Test::*member=nullptr;
    cout << typeid(getPointerType<decltype(member)>::type).name() << std::endl;
    return 0;
}

输出将是预期的 "i"。

这正是我要找的。如果我理解正确,由于“成员”不是const,所以无法使用“getPointerType<member> ::type”语法来创建库。是否可以通过getPointerType<decltype(member)>::type实现?还是getPointerType(member).type(我尝试过这个:“template <class C,typename T>结构getPointerType {getPointerType(T C ::* v); {}typedef T type;};”,但是这会导致缺少模板参数的错误)。 - ted
1
好的,已编辑帖子以包括 getPointerType<decltype(member)>::type - oakad

3

这里有一个使用模板特化技术的解决方案:

#include <type_traits>

template <class T>
struct member_type_helper;

template <class C, class T>
struct member_type_helper<T C::*> { using type = T; };

template <class T>
struct member_type
    : member_type_helper<typename std::remove_cvref<T>::type> {};

// Helper type
template <class T>
using member_type_t = member_type<T>::type;

使用示例:

#include <iostream>

struct Foo { int i; };

int main()
{
    auto                ptr1 = &Foo::i;
    auto const&         ptr2 = &Foo::i;
    volatile auto const ptr3 = &Foo::i; // let's go crazy

    // prints true true true
    std::cout << std::boolalpha
              << std::same_as<int, member_type_t<decltype(ptr1)>> << '\n'
              << std::same_as<int, member_type_t<decltype(ptr2)>> << '\n'
              << std::same_as<int, member_type_t<decltype(ptr3)>> << '\n';
}

我猜 std::remove_cvref 对于大多数用途来说可能有些过度,但是嘿,它是免费的。如果你的编译器不符合>C++20标准,你可以使用std::remove_cv代替(> C++11)。



网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接