Указатель на член, дескрипторы типов и ссылки - PullRequest
0 голосов
/ 03 декабря 2011

Я работаю над проектом дескриптора типа в 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 ++, как я узнал ранее на этой неделе: https://stackoverflow.com/a/8336479/1074536,, поэтому я не могу использовать & Foo :: refToAndInt например.

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

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

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

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

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

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

Спасибо!

1 Ответ

0 голосов
/ 05 декабря 2011

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

  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);

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

...