我想提取成员指针指向的成员类型。
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>>
,
someType
uint32_t
我收到以下错误消息:
错误:类型中的static_cast无效 '__gnu_cxx::__alloc_traits>::value_type {aka unsigned char}' 键入 'uint32_t& {aka unsigned int&}'
据我了解,decltype(instance.*member)
member
定义为uint32_t instance::*member
会产生参考uint32_t&
而不是uint32_t
。我尝试按值传递实例,但错误仍然存在。我知道std::remove_reference
但是,我不明白参考首先是如何出现的。
进一步的改进是,如果我可以在没有类实例的情况下提取someType
。但是我不知道如何实现这一点,而我可以通过拥有 std lib 来获取没有指针的类,例如:
template <T*>
struct removePointer {
typedef T type;
}
我不知道如何以一种形式编写它,我可以在不先了解类的情况下获得类的someType
部分。我可以写如下内容,但是我仍然必须显式传递类naem和typename,有没有办法自动提取它们?此外,以下 doe 首先不会编译 (http://ideone.com/8VlKO4): #include 使用命名空间标准;
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;
}
坦率地说,要理解您要实现的目标有点困难,因此我将专注于更新的部分。
显然,您不能将类型(派生自 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"。
以下是使用模板专用化技术的解决方案:
#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)。