Преобразование в C ++: указатель на член объекта, вычисление указателя на объект

C ++ имеет static_cast преобразовать base_class_pointer в derived_class_pointer,

Это очень похожая операция для преобразования object_data_member_pointer в object_pointer,

Я написал функцию ConvertDataMemberPtrToObjectPtr используя небезопасное преобразование типа C.

  • Как это можно сделать безопасным способом? Ссылка на член должна быть указана в качестве параметра шаблона member_ptr,
  • Могут ли возникнуть какие-либо проблемы, если вы используете такую ​​реализацию?

Источник:

#include <stdio.h>
#include <tchar.h>

template< class T, class Member_type, Member_type T::*member_ptr >
inline T *ConvertDataMemberPtrToObjectPtr(Member_type& member) {
//Got reference to member 'member' of object 'T', return pointer to object 'T'
// obj_ptr = member_ptr - offset_of_member_field
return (T*) ( ((char*)(&member)) - ( (char*) (  &( ((T*)(0))->*member_ptr ) )  ) );
}

struct Test {
int a;
int b;
};

int _tmain(int argc, _TCHAR* argv[]) {

Test obj;

printf("\n0x%08lX", ConvertDataMemberPtrToObjectPtr<Test,int,&Test::a>(obj.a));
printf("\n0x%08lX", ConvertDataMemberPtrToObjectPtr<Test,int,&Test::b>(obj.b));

// This is must be avoided when using ConvertDataMemberPtrToObjectPtr!!!
printf("\n0x%08lX - error!", ConvertDataMemberPtrToObjectPtr<Test,int,&Test::a>(obj.b));

return 0;
}

Использование родителей вместо членов и static_cast:

template <class T, int id=0>
class Link {
public:
int value;
T *GetObjectPtr() { return static_cast<T*>(this); }
};
enum MyLinkId { Main=0, Red=1 };
class MyItem : public Link<MyItem,Main>, public Link<MyItem,Red> {};

MyItem x;
Link<MyItem,Main> *p2 = &x;
Link<MyItem,Red> *p3 = &x;

printf("\n0x%08lX", p2->GetObjectPtr());
printf("\n0x%08lX", p3->GetObjectPtr());

3

Решение

То, чего вы пытаетесь достичь, невозможно: отсутствует информация, позволяющая различать членов.
Вам понадобится уникальный ссылочный элемент, который вы можете передать своей функции преобразования.

struct UniqueReferenceMember {};
struct Test {
UniqueReferenceMember unique_reference_member;
int a;
int b;
};

Иметь это бессмысленно. Есть указатель объекта, который вы можете передать напрямую (может быть преобразован в void *);

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]