Указатель на член, дескрипторы типов и ссылки

Я работаю над проектом дескриптора типа в C++11. Работа дескриптора типа заключается в том, чтобы знать типы каждого члена класса, его размер и смещение от основания объекта. Я не поддерживаю множественное наследование, а также объекты с виртуальными методами, поэтому сейчас я делаю это намного проще. Цель состоит в том, чтобы иметь возможность сериализации и десериализации объектов с использованием дескриптора.

Обратите внимание, что это любимый проект, который возиться с такими функциями, как шаблоны с переменным числом аргументов, указатель на члены и другие функции C++, с которыми я не знаком, поэтому нет необходимости указывать мне что-то вроде boost:: archiving. :)

То, как я на самом деле регистрирую участников, очень похоже на путь boost:: python:: class_.

ClassDescriptor fooDesc( "Foo" );
fooDesc.addMember( "a", &Foo:: a );
fooDesc.addMember( "b", &Foo:: b );

// (abridged for clarity) :
template< typename ClassType, typename MemberType >
ClassDescriptor& ClassDescriptor::addMember(
  const char* name,
  MemberType ClassType::* member
)
{
   return addMember< MemberType >( name, reinterpret_cast< size_t >( &(((ClassType*)0)->*member)) );
}

К сожалению, функция указателя на член C++ не может использоваться со ссылками в C++, как я узнал ранее на этой неделе: /questions/28996448/ukazatel-na-uchastnika-kotoryij-yavlyaetsya-nezakonnoj-ssyilkoj/28996455#28996455, поэтому я не могу используйте &Foo::refToAndInt, например.

Что касается того, как я вычисляю смещение члена, я не использую смещение макроса, так как мои классы не всегда будут POD.

Так как я не могу использовать указатели на члены для вычисления смещения ссылок, я решил попробовать:

&(((Foo*)nullptr)->refToAnInt)

но если это было указано в другом потоке переполнения стека, это неопределенное поведение и, очевидно, в LLVM происходит сбой.:(

Я хотел бы избегать таких вещей, как смещение предыдущего члена, добавление его размера и последующее вычисление отступа, необходимого для выравнивания моего следующего члена, так как это выглядело бы грязно и подвержено ошибкам

Так что я не могу использовать оба этих трюка, а offsetof предназначен только для POD. Любое предложение о том, что я мог бы попробовать дальше, кроме моего другого ужасного предложения?

Спасибо!

1 ответ

Согласно стандарту,

  1. Классы

    6 ... Тривиально класс - это класс, имеющий тривиальный конструктор по умолчанию (12.1) и......

    10 POD структура - это класс, который является одновременно тривиальным классом и......

12.1 Конструкторы

5 ...

 A default default constructor for class X is defined as deleted if:

 ...

 - any non-static data member with no brace-or-equal-initializer is of

ссылочный тип,

 ...

 A default constructor is trivial if it is neither user-provided nor deleted

и если

 ...

 - for all the non-static data members of its class that are of class type(or

их массив), каждый такой класс имеет тривиальный конструктор по умолчанию.

Безусловно, любой класс, имеющий ссылочный член, не может быть POD, если не существует инициализатора скобок или равно, например:

class A
{
    A &me=*this;
};

Если это так, вы можете создать конкретный обходной путь.

Для проблемы

&(((Foo*)nullptr)->refToAnInt)

Вы можете попробовать следующее:

std::aligned_storage<sizeof(Foo), std::alignment_of<Foo>::value>::type storage;
&((static_cast<Foo *>(static_cast<void *>(&storage)))->refToAnInt);

Его поведение должно быть четко определено.

Другие вопросы по тегам