Re[2]: расмоложение мемберов класса в памяти
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 13.06.10 20:49
Оценка: +2
Здравствуйте, szag, Вы писали:

S>это работает, но как-то это не по-казачьи. Может кто-то предложет что-то получше?


Не надо так делать, ты вносишь дополнительные зависимости, которые очень сложно отлавливать. Расскажи про саму задачу. Почти наверняка есть какой-то удобоваримый способ решения, без колдунства.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re: расмоложение мемберов класса в памяти
От: R.O. Prokopiev Россия http://127.0.0.1/
Дата: 14.06.10 19:07
Оценка: :))
Здравствуйте, szag, Вы писали:

Для размоложения можно использовать Фонтан Старости
http://ru.wikipedia.org/wiki/Teenage_Mutant_Leela%27s_Hurdles
Re[12]: расмоложение мемберов класса в памяти
От: Кодт Россия  
Дата: 16.06.10 07:59
Оценка: 3 (1)
Здравствуйте, szag, Вы писали:

S>fields представляет из себя поток дефайнов, вида:

S>
S>INT(id, 50, INITVALUE(100))
S>STRING(name, 100, 60, INITVALUE(L"TestDefaultString"))
S>DATE(birthday, 10)
S>TIME(localtime, 31)
S>BOOL(IsOk, 25)
S>DOUBLE(pisun, 45)
S>

Это очевидно.

S>каждый дефайн вызывает другой дефайн,

А вот здесь мы вас поправим! Пусть этот дефайн не сам вызывает макрос FIELD(.....), а его извне заставляют вызвать тот или иной макрос.
И у нас есть два контекста:
— объявление членов структуры (то, что сейчас уже делается)
— заполнение массива метаданных

S> который формирует класс делает следующее:

S>#define FIELD(TypeID, RealType, name, captionID, ...)            \
S>class RealType ## _ ## name : public ORMfield<TypeID, RealType>      \

Такие склейки лучше делать опосредованно:
#define MAKE_TYPE_NAME(name) MAKE_TYPE_NAME_(name)
#define MAKE_TYPE_NAME_(name) RealType##_##name

Во-первых, гарантируем, что склеиваться будет окончательное значение name. Во-вторых, просто нагляднее, и избегаем повторения операции (она встречается здесь четырежды: в имени класса, в конструкторе, в sizeof и в типе переменной).

S>в общем-то функция GetSize сейчас уже включает в себя выравнивание поля.

По-моему, это неправильно. В размер нужно добавлять величину зазора между этим полем и следующим. А тип следующего поля неизвестен.
Хотя... может быть, и можно так делать.
Перекуём баги на фичи!
Re[12]: расмоложение мемберов класса в памяти
От: Erop Россия  
Дата: 16.06.10 08:30
Оценка: 3 (1)
Здравствуйте, szag, Вы писали:

S>
S>#define FIELD(TypeID, RealType, name, captionID, ...)            \
S>class RealType ## _ ## name : public ORMfield<TypeID, RealType>      \
S>{                                                                    \
S>public:                                                              \
S>    explicit RealType ## _ ## name () : ORMfield(#name , captionID)  \
S>    {                                                                \
S>        InitValue(FieldValue);                                       \
S>    }                                                                \
S>                                                                     \
S>   // куча кода опущена                                                                  \
S>                                                                     \
S>    std::size_t GetSize() const                                      \
S>    {                                                                \
S>        return sizeof( RealType ## _ ## name ) +                     \
S>            MyAlign<RealType ## _ ## name>::Result;                  \
S>    }                                                                \
S>                                                                     \
S>    __VA_ARGS__                                                      \
S>                                                                     \
S>};                                                                   \
S>                                                                     \
S>RealType ## _ ## name name;
S>


Вот! Наконец-то попёрла конкретика!
Только всё равно не понятно, что такое TypeID и зачем он нужен.
Ещё не совсем мне понятно, зачем нужно чтобы на каждое поле был свой класс? Из-за инициализатора только?
IMHO, можно так не делать, а инициализаторы передавать в конструкторе таблицы.

Но я не про это.
Во-первых, даже с классом на каждое поле, конструкцию можно упростить.

Типа написать шаблон
template<typename MDT, typename TypeID, typename TRealType> 
class ORMfield {
//  тут всё так, как у тебя и есть +
    std::size_t GetSize() const;
    {                                                                \
        return sizeof( RealType ## _ ## name ) +                     \
            MyAlign<RealType ## _ ## name>::Result;                  \
    }                                                                \
 
};
template<typename MDT, typename TypeID, typename TRealType>
std::size_t GetSize();
{                                                                
    return sizeof( MDT ) + MyAlign<MDT>::Result;                 
}


Во-вторых, на сколько я понял, место тебе не жаль?
Тогда можно сдать так, что все ORMfield будут выравниваться одинаково. На что-то одно и то же, достаточно большое.
Ну, например, иметь такой вот простенький шаблон:
template<typename T, typename TAlignAs = double> class AlignedData {
    union {
        TAlignAs dummy;
        char buffer[sizeof( T )];
    } data;
public:
    AlignedData() { new( data.buffer ) T; }
    AlignedData( const AlignedData& other ) { new( data.buffer ) T( other.Get() ); }
    template<typename T1>
    AlignedData( T1 t1 )  { new( data.buffer ) T( t1 ); }
    template<typename T1, typename T2>
    AlignedData( T1 t1, T2 t2 )  { new( data.buffer ) T( t1, t2 ); }
    ~AlignedData() { Get().~T(); }

    void operator = ( const AlignedData& other ) { Get() = other.Get(); }

    T& Get() { return *static_cast<T*>( data.buffer ); }
    const T& Get() const { return *static_cast<const T*>( data.buffer ); }
};


И внутри ORMfield хранить все данные в виде AlignedData<RealType>
Тогда на GetSize можно будет просто забить, а сделать у всех ORMfield общую базу, типа ORMfieldBase и заиметь у неё метод virtual const ORMfieldBase* GetNext() const...


S>fields представляет из себя поток дефайнов, вида:
S>
S>INT(id, 50, INITVALUE(100))
S>STRING(name, 100, 60, INITVALUE(L"TestDefaultString"))
S>DATE(birthday, 10)
S>TIME(localtime, 31)
S>BOOL(IsOk, 25)
S>DOUBLE(pisun, 45)
S>


Что касается той идеи, что предлагал КодТ, то там всё просто.

Я напишу так, словно у тебя есть только тип int и немного на псевдокоде, а ты обобщишь потом на всё, что тебе надо.
Пишешь, такую систему макросов:
#define EXTRACT_FIELDS_END_OF_LIST_
#define EXTRACT_FIELDS_INT( NAME, TYPE_ID, INIT_VALUE ) \
    /* тут собственно кусок твоего старого определение INT */ FIELD( int, NAME, TYPE_ID, INIT_VALUE )\
    EXTRACT_FIELDS_##
EXTRACT_FIELDS( FIELDS ) EXTRACT_FIELDS_##FIELDS END_OF_LIST_ 
// Тут, на самом деле, надо немного схимичить, чтобы FIELDS подставилось раньше, чем развернётся, но я пока не буду


Потом пишешь ещё макросы EXTRACT_INITIALIZATORS_LIST, EXTRACT_TABLE_OF_OFFSETS и т. д. и живёшь себе счастливо без виртуальных функций GetSize

Да, по поводу "схимичить" всё уже схимичено в бусте. Если ты не можешь его заюзать, а IMHO, это жёсткое требованиек клиентам -- доставить буст. Ты можешь выдрать химию оттуда, или попроси, тебе тут помогут.

Вот.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[11]: расмоложение мемберов класса в памяти
От: Кодт Россия  
Дата: 16.06.10 15:18
Оценка: 3 (1)
К>Завтра попробую на BOOST/PP родить рабочий пример.

#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/facilities/expand.hpp>
#include <boost/preprocessor/punctuation/paren.hpp>
#include <boost/preprocessor/tuple/elem.hpp>

// T_xxx - макросы для внутреннего использования

// генератор структуры
#define TABLE(name,meta,fields) \
    struct name : ORMTableBase { \
        meta \
        BOOST_PP_SEQ_FOR_EACH(T_APPLY, (T_MEMBER,name), fields) \
        static const FieldInfo* reflection() { \
            static const FieldInfo refs[] = { \
                BOOST_PP_SEQ_FOR_EACH(T_APPLY, (T_REFLECTION,name), fields) \
                {} \
            }; \
            return refs; \
        } \
    }; \
    //ENDMACRO

// колбеки - генераторы элементов
#define T_MEMBER(name,type,var,...) type var;
#define T_REFLECTION(name,type,var,...) { BOOST_PP_STRINGIZE(var), sizeof(type), _offsetof(name,var) },

// T_APPLY - общий колбек (высшего порядка!) для макроса FOR_EACH
// принимает 3 параметра (r,data,elem)
// r - номер следующего элемента, - т.е. 2, 3, 4, и т.д. - бустовские штучки
// data - общий параметр, у нас это (T_MEMBER,name) или (T_REFLECTION,name) - т.е. колбек + имя класса
// elem - элемент серии, т.е. информация об очередном поле (type,var,etc...)

// T_APPLY(r,(macro,name),(type,var,etc...)) --> T_APPLY_( macro, name, type,var,etc... ) -- последняя пачка идёт одним аргументом!
#define T_APPLY(r,mn,fld) \
    BOOST_PP_EXPAND( \
        T_APPLY_(BOOST_PP_TUPLE_ELEM(2,0,mn), BOOST_PP_TUPLE_ELEM(2,1,mn), T_UNWRAP fld) \
    ) \
    //ENDMACRO
#define T_APPLY_(macro,name,fld) macro BOOST_PP_LPAREN() name,fld ) // --> macro ( name , type,var,etc... )

#define T_UNWRAP(...) __VA_ARGS__ // (x,y,z,t) --> x,y,z,t


// тестируем...
TABLE(foo, hello, ((int,x)) ((char,y)) )

// на выходе получилось
struct foo : ORMTableBase {
    hello
    int x;
    char y;
    static const FieldInfo* reflection() {
        static const FieldInfo refs[] = {
            { "x", sizeof(int), _offsetof(foo,x) },
            { "y", sizeof(char), _offsetof(foo,y) },
            {}
        };
        return refs;
    }
};
Перекуём баги на фичи!
расмоложение мемберов класса в памяти
От: szag  
Дата: 13.06.10 13:14
Оценка:
есть задача обращаться к полям класса по их имени, т.е. зная строку. Это строка, приходит, парсится потом собственно идет само обращение.
Каждое поля класса это класс, интерфейс которого нам известен.
Придумал вот такую функцию, которую вызываю из констактора и заполняю мап со смещениями для всех полей:
bool ORMtableBase::FillFiledsMap(FieldsList& fields, const ORMtableBase* _this)
{
    size_t Finish = _this->GetSize(); // size of main class
    size_t Start = _this->GetFirstField(); // offset to first field
    while(Start < Finish)
    {
        const IORMField* pField = 
            static_cast<const IORMField*> // common interface for each field
            (
                static_cast<const void*>
                (
                    (
                        static_cast<const char*>
                        (
                            static_cast<const void*>(_this)
                        ) + Start
                    )
                )
            );
        fields.insert(std::pair<std::string, FieldInfo>(pField->GetName(), FieldInfo(pField->GetType(), Start))); // sometimes it crashes here
        Start += pField->GetSize(); // sizeof(ClassFieldName)
    }
    return !fields.empty();
}

и все замечательно работает на 32-х машинах, но на 64-х битных возникает крэш, ровно для одного из типов, который возвращает размер 42, а реально смещение до следующего поля 46. Выравниваение во всех проектах стоит 8 байт. Это похоже на проблему выравнивания и можно было ббы написать функцию, которая бы подравнивала такие значения, вот только будет ли это гарантированно правильно во всех компиляторах?

P.S. Все эти извращения потому, что в месте использования нет информации о конечном типе, а есть только интерфейс.
Re: расмоложение мемберов класса в памяти
От: superlexx  
Дата: 13.06.10 13:43
Оценка:
Здравствуйте, szag, Вы писали:

S>Выравниваение во всех проектах стоит 8 байт.


default alignment для 32-bit и 64-bit разные (MSVC: 8 и 16 соотв.).
Re[2]: расмоложение мемберов класса в памяти
От: szag  
Дата: 13.06.10 14:10
Оценка:
Здравствуйте, superlexx, Вы писали:

S>default alignment для 32-bit и 64-bit разные (MSVC: 8 и 16 соотв.).


смещение установлено явно — 8 byte для всех проектов.
Re: расмоложение мемберов класса в памяти
От: dilmah США  
Дата: 13.06.10 14:38
Оценка:
я не понимаю, ты хочешь сказать что offsetof неправильно работает?
Re[2]: расмоложение мемберов класса в памяти
От: szag  
Дата: 13.06.10 15:18
Оценка:
Здравствуйте, dilmah, Вы писали:

D>я не понимаю, ты хочешь сказать что offsetof неправильно работает?

он работает правильно, но я не могу его использовать для всех членов класса. Могу только для первого.
Я же хотел сказать что offsetof != sizeof() для некоторых полей, sizeof() == 42, а оffsetof 46 из-за выравнивания.
Re: расмоложение мемберов класса в памяти
От: szag  
Дата: 13.06.10 15:21
Оценка:
в общем пока придумал вот такую конструкцию
template<class T, std::size_t val = sizeof(T)>
struct MyAlign
{
    enum
    {
        Result = ((val / 8) * 8 == val) ? 0 : (((val / 8) + 1) * 8) - val
    };
};

это работает, но как-то это не по-казачьи. Может кто-то предложет что-то получше?
Re[2]: расмоложение мемберов класса в памяти
От: Seigram  
Дата: 13.06.10 20:07
Оценка:
Здравствуйте, szag, Вы писали:

S>в общем пока придумал вот такую конструкцию

S>
S>template<class T, std::size_t val = sizeof(T)>
S>struct MyAlign
S>{
S>    enum
S>    {
S>        Result = ((val / 8) * 8 == val) ? 0 : (((val / 8) + 1) * 8) - val
S>    };
S>};
S>

S>это работает, но как-то это не по-казачьи. Может кто-то предложет что-то получше?

1. 'offsetof' корректно(гарантированно) работает для POD
2. почему не использовать указатели(враперы для указателей) на члены класса для обращения к таковым?
т.к. Ваша реализация(вычисления) вероятно сильно будет зависить от реализации/настроек компилятора,
и/или не учитывает #pragma pack's, а у Вас не видно использований 'alignof'(MSVC '__alignof'). И т.п.
Если считать( ) то более корректно с учетом ниже сказанного.
2.a) заменить "8" на что-то типо:
struct someStruct {};
int opt=alignof(someStruct); // get compiler option 'alignment'
2.b) учесть выравнивание самого класса(влияние #pragma pack's)
3.
Re: расмоложение мемберов класса в памяти
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 13.06.10 20:45
Оценка:
Здравствуйте, szag, Вы писали:

S>P.S. Все эти извращения потому, что в месте использования нет информации о конечном типе, а есть только интерфейс.


Странная какая-то затея. Чем тебе offsetof() не нравится? Собственно, никто никому не обещает, что сумма размеров членов даст в результате правильное смещение следующего члена. Тут ещё куча вопросов по ходу дела, например, зачем обращаться по смещению (!), одновременно скрывая информацию о классе? Чтоб спрашивали, что ли? Давай, ты лучше про саму задачу расскажешь.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re: расмоложение мемберов класса в памяти
От: Seigram  
Дата: 13.06.10 21:52
Оценка:
Здравствуйте, szag, Вы писали:
[skipped]

S>P.S. Все эти извращения потому, что в месте использования нет информации о конечном типе, а есть только интерфейс.


Я думаю, — решение можно представить в виде регистратора(статического) объектов(рожденных от class Object)
Примерно так:

//------------------------------------------------------------------------------
class Object {
public:
Object();
virtual ~Object() = 0;
string getName();
static Object* findObjectByName(const string &name);
/*
* Здесь Ваш "известный" интерфейс, вероятно virtual some_result_type1(-N) some_fun1(-N)(arg_list1-(-N)) = 0;
*/
protected:
typedef map<string, Object*> c_objReg;
typedef c_objReg::iterator c_objRegI;
// регистр объектов
static c_objReg objReg;
// имя
string name;
// запрос на регистрацию объекта с конкретным именем
bool registerName(const string &in_name);
};
//------------------------------------------------------------------------------
Object::c_objReg Object::objReg=Object::c_objReg();
//------------------------------------------------------------------------------
Object::Object() {}
//------------------------------------------------------------------------------
Object::~Object() {}
//------------------------------------------------------------------------------
string Object::getName() {
return name; // или typeid(*this).name()
}
//------------------------------------------------------------------------------
Object* Object::findObjectByName(const string &name) {
return objReg[name];
}
//------------------------------------------------------------------------------
bool Object::registerName(const string &in_name) {
if (in_name.size() && objReg.insert(make_pair(in_name, this)).second)
name=in_name;
return true;
}

Соответственно в конструкторах производных классов сделать registerName(typeid(*this).name()); или произвольное(удобное) имя

class foo1: public Object {
public:
foo1() { registerName("Object_foo1"); }
};
class foo2: public Object {
public:
foo2() { registerName("Object_foo2"); }
};

Найти его: Object::findByName(<desired_object_name>);
Re[2]: расположение мемберов класса в памяти
От: szag  
Дата: 14.06.10 08:04
Оценка:
Здравствуйте, Seigram, Вы писали:

S>Я думаю, — решение можно представить в виде регистратора(статического) объектов(рожденных от class Object)


я думал о чем-то подобном, однако такой подход имеет ряд недостатков и накладывает определенные обязанности на пользователя библиотеки, чего не хотелось бы.
Библиотека представляет из себя либу + хидер. На вход получает класс унаследованный от определенного, заранее известного интерфейса, либа заправшивает данные и они приходят в виде xml. потом она заполняет поля класса значениями и возвращает true. Все возможные типы полей заранее известны, точнее известны типы данных хранящихся там. Сами поля представляют из себя сборку класса из нескольких темплейтов, в зависимости от того что ввел пользователь библиотеки, так как поля содержат всякую информацию, к примеру для строк максимальную длинну. таких полей в классе может быть от нескольких штук до нескольких десятков и ничего с этим не поделаешь, если так пожелает пользователь. Поэтому не хотелось бы делать вариант с регистрацией и заставлять пользователя регистрировать все имена полей. По условиям задачи в классе не может быть лишних, системных, не нужных и прочих полей — все именно поля необходимые для заполнения, поэтому не хотелось бы давать лишнюю гибкость пользователю.
Сейчас это сделано с помощью макроса, который собирает класс из темплейтов и создает поле, а пользователю достаточно написать:
FIELD(MyName, 50, INITVALUE("Ivan"))

Соответственно создастся поле, с максимальной длинной 50 и по умолчанию будет инициализировано как "Ivan". Вещей, подобных INITVALUE, может быть несколько (есть обязательные и не обязательные), все примеры приводить не буду, но думаю общий смысл понятен. Сейчас все эти вещи проверяются на этапе компиляции и удобны для пользователя библиотеки.
Re[3]: расположение мемберов класса в памяти
От: Seigram  
Дата: 14.06.10 09:54
Оценка:
Здравствуйте, szag, Вы писали:

S>Здравствуйте, Seigram, Вы писали:


S>>Я думаю, — решение можно представить в виде регистратора(статического) объектов(рожденных от class Object)


S>я думал о чем-то подобном, однако такой подход имеет ряд недостатков и накладывает определенные обязанности на пользователя библиотеки, чего не хотелось бы.

S>Библиотека представляет из себя либу + хидер. На вход получает класс унаследованный от определенного, заранее известного интерфейса, либа заправшивает данные и они приходят в виде xml. потом она заполняет поля класса значениями и возвращает true. Все возможные типы полей заранее известны, точнее известны типы данных хранящихся там. Сами поля представляют из себя сборку класса из нескольких темплейтов, в зависимости от того что ввел пользователь библиотеки, так как поля содержат всякую информацию, к примеру для строк максимальную длинну. таких полей в классе может быть от нескольких штук до нескольких десятков и ничего с этим не поделаешь, если так пожелает пользователь. Поэтому не хотелось бы делать вариант с регистрацией и заставлять пользователя регистрировать все имена полей. По условиям задачи в классе не может быть лишних, системных, не нужных и прочих полей — все именно поля необходимые для заполнения, поэтому не хотелось бы давать лишнюю гибкость пользователю.
S>Сейчас это сделано с помощью макроса, который собирает класс из темплейтов и создает поле, а пользователю достаточно написать:
S>
S>FIELD(MyName, 50, INITVALUE("Ivan"))
S>

S>Соответственно создастся поле, с максимальной длинной 50 и по умолчанию будет инициализировано как "Ivan". Вещей, подобных INITVALUE, может быть несколько (есть обязательные и не обязательные), все примеры приводить не буду, но думаю общий смысл понятен. Сейчас все эти вещи проверяются на этапе компиляции и удобны для пользователя библиотеки.

Чесно? -Объяснение не понятное. И что такое "сборку класса из нескольких темплейтов" — агрегация или наследование используется?
Далее, про вышесказанное "колдунство" с формулами, — при данных условиях(вернее ограничениях), по видимому без него не обойтись, но необходимо знать как компилятор размещает в памяти члены класса. И 1-е на чем ты накололся это выравнивания членов класса, т.е.
как правило(если члены не char's все) то sum[sizeof(member[i]] != sizeof(структура их содержащая).
Потому что(цитирую): "структура выравнивается на максимальное выравнивание среди полей. Каждое поле выравнивается на выравнивание типа поля".
И если ты хочешь правильного колдунства, то должен это учесть; как я уже сказал ответами выше есть оператор alignof()/__alignof() который это разрешает узнавать, и — offsetof корректен только для POD типов.
В каком то смысле ты должен имитировать функцию компилятора отвечающую за вычесление размещения.
Re: расмоложение мемберов класса в памяти
От: nen777w  
Дата: 14.06.10 10:15
Оценка:
Я вот когда то писал для своего компилятора вот такой вот класс.
Может тебе пригодится.

#ifndef __struct_alignment_calculator_h__
#define __struct_alignment_calculator_h__

#include <vector>
#include "basic_defines.h"
#include "math_algorithms.h"

namespace logical_algs
{
    struct type_dsk
    { 
        type_dsk( unsigned int size, unsigned int alignment, unsigned int elements = 1 ) 
            : m_sizeof(size) 
            , m_alignment(alignment)
            , m_offset(0)
            , m_padding(0)
            , m_elements(elements)
        {}
        type_dsk()
            : m_sizeof(0)
            , m_alignment(0)
            , m_offset(0)
            , m_padding(0)
            , m_elements(1)
        {}

        unsigned int get_sizeof() const { return m_elements * m_sizeof; }

        unsigned int m_offset;
        unsigned int m_padding;

        unsigned int m_sizeof;
        unsigned int m_alignment;
        unsigned int m_elements;
    };

    struct struct_dsk : public type_dsk
    {
        enum ealgnment {
             algnt_def  = 0
            ,algnt_1    = 1
            ,algnt_2    = 2
            ,algnt_4    = 4
            ,algnt_8    = 8
            ,algnt_16   = 16
        };
        typedef std::vector<type_dsk> v_fields;

        void     recalculate( ealgnment algn )
        {
            unsigned int c_f_o = 0;
            unsigned int c_s_a = 1;

            v_fields::iterator it = m_fields.begin();
            for(; it != m_fields.end(); ++it ) 
            {
                c_s_a = pg_max( c_s_a, (*it).m_alignment );
                if( algnt_def != algn ) {
                    c_s_a = pg_min( c_s_a, (unsigned int)algn );
                    (*it).m_alignment = pg_min( c_s_a, (*it).m_alignment);
                }
                c_f_o = math_algs::nearest_up_multiple( c_f_o, (*it).m_alignment );
                (*it).m_offset = c_f_o;
                c_f_o += (*it).get_sizeof();
                if( m_fields.begin() != it ) {
                    (*(it-1)).m_padding = (*it).m_offset - ( (*(it-1)).m_offset + (*(it-1)).get_sizeof() );
                }
            }

            m_sizeof = math_algs::nearest_up_multiple( c_f_o, c_s_a );
            m_alignment = c_s_a;
            (*m_fields.rbegin()).m_padding = m_sizeof - ( (*m_fields.rbegin()).m_offset + (*m_fields.rbegin()).get_sizeof() );
        }

        v_fields m_fields;
    };
}

#endif


Немного пояснений:
pg_min, pg_max — это обычные макросы min/max

math_algs::nearest_up_multiple — это:
    int nearest_up_multiple( int from, int multiple )
    {
        return (int)( multiple * ceil(((double)from)/multiple) );
    }



Юзать так:

#define ALIGNMENT  8

#if ALIGNMENT != 0
#pragma pack(push, ALIGNMENT)
#endif
    struct K
    {
        char    a; 
        double  b; 
        char    c[15];
        int     d; 
        char    e; 
    };

    struct K1
    {
        char x;   
        K    y[3];   
        int  z;   
    };
#if ALIGNMENT != 0
#pragma pack(pop)
#endif

    int tk_s = sizeof(K);
    int tk_1 = offsetof(K, a);
    int tk_2 = offsetof(K, b);
    int tk_3 = offsetof(K, c);
    int tk_4 = offsetof(K, d);
    int tk_5 = offsetof(K, e);

    struct_dsk Kdsk;
    Kdsk.m_fields.push_back( type_dsk( sizeof(char), sizeof(char) ) );
    Kdsk.m_fields.push_back( type_dsk( sizeof(double), sizeof(double) ) );
    Kdsk.m_fields.push_back( type_dsk( sizeof(char), sizeof(char), 15 ) );
    Kdsk.m_fields.push_back( type_dsk( sizeof(int), sizeof(int) ) );
    Kdsk.m_fields.push_back( type_dsk( sizeof(char), sizeof(char) ) );
    Kdsk.recalculate( (struct_dsk::ealgnment)ALIGNMENT );

    assert( tk_1 == Kdsk.m_fields[0].m_offset );
    assert( tk_2 == Kdsk.m_fields[1].m_offset );
    assert( tk_3 == Kdsk.m_fields[2].m_offset );
    assert( tk_4 == Kdsk.m_fields[3].m_offset );
    assert( tk_5 == Kdsk.m_fields[4].m_offset );
    assert( tk_s == Kdsk.m_sizeof );
   
    int tk1_s = sizeof(K1);
    int tk1_1 = offsetof(K1, x);
    int tk1_2 = offsetof(K1, y);
    int tk1_3 = offsetof(K1, z);

    struct_dsk K1dsk;
    K1dsk.m_fields.push_back( type_dsk( sizeof(char), sizeof(char) ) );
    K1dsk.m_fields.push_back( type_dsk( Kdsk.m_sizeof, Kdsk.m_alignment, 3 ) );
    K1dsk.m_fields.push_back( type_dsk( sizeof(int), sizeof(int) ) );
    K1dsk.recalculate( (struct_dsk::ealgnment)ALIGNMENT );

    assert( tk1_1 == K1dsk.m_fields[0].m_offset );
    assert( tk1_2 == K1dsk.m_fields[1].m_offset );
    assert( tk1_3 == K1dsk.m_fields[2].m_offset );
    assert( tk1_s == K1dsk.m_sizeof );
Re[2]: расмоложение мемберов класса в памяти
От: Seigram  
Дата: 14.06.10 10:37
Оценка:
Здравствуйте, nen777w, Вы писали:
[skipped]

Просто интересно, а зачем выравнивание если вокруг него(именно в данной ситуации) возникает столько проблем. Можно охватить все pack(push,1)|pack(pop) тогда очевидно даже 1-й код приведенный автором "сойдется".
Re[4]: расположение мемберов класса в памяти
От: szag  
Дата: 14.06.10 10:42
Оценка:
Здравствуйте, Seigram, Вы писали:

S> Чесно? -Объяснение не понятное. И что такое "сборку класса из нескольких темплейтов" — агрегация или наследование используется?


Используется и агрегация и наследование (но это не важно), в конечном коде это будет выглядеть так (привожу упрощенный пример):

class MyClass : public iClassBase
{
public:
    int i1, i2, i3; // 3 поля гарантированные для этого класса
    std::size_t GetFirstField() const
    {
        return offsetof(MyClass, i3) + sizeof(int);
    }
    std::size_t GetSize() const
    {
        return sizeof(MyClass);
    }
    // ниже идут поля класса
    class MyField : public MyFieldBase
    {
    public:
        MyField() {/*здесь будет код*/}
        std::size_t GetSize() const
        {
             return sizeof(MyField) + MyAlign<MyField>::Result;
        } 
    };
    MyField Fild1Name;
    /* и так далее для каждого поля */
};


S>Далее, про вышесказанное "колдунство" с формулами, — при данных условиях(вернее ограничениях), по видимому без него не обойтись, но необходимо знать как компилятор размещает в памяти члены класса. И 1-е на чем ты накололся это выравнивания членов класса, т.е.

S>как правило(если члены не char's все) то sum[sizeof(member[i]] != sizeof(структура их содержащая).

Я с этим согласен, поэтому и спросил совета — как лучше сделать.

S>Потому что(цитирую): "структура выравнивается на максимальное выравнивание среди полей. Каждое поле выравнивается на выравнивание типа поля".

S>И если ты хочешь правильного колдунства, то должен это учесть; как я уже сказал ответами выше есть оператор alignof()/__alignof() который это разрешает узнавать, и — offsetof корректен только для POD типов.
S>В каком то смысле ты должен имитировать функцию компилятора отвечающую за вычесление размещения.

Да, вы правы насчет POD типов, но, к сожалению, у меня они не POD и с этим сложно что-либо поделать. Мне необходимо чтобы этот код можно было использовать под виндами 32/64 бит и *nix 32/64. Поэтому необходима совместимость с гсс. И конечно хотелось бы чтобы была гарантия со стороны стандарта.
Re: расмоложение мемберов класса в памяти
От: Тролль зеленый и толстый  
Дата: 14.06.10 15:33
Оценка:
Используй указатели на члены класса, а не трюки с offset'ов. У меня в одном проекте подобная задача — это, фактически, рефлексия для C++.
Re[2]: расмоложение мемберов класса в памяти
От: szag  
Дата: 14.06.10 15:37
Оценка:
Здравствуйте, Тролль зеленый и толстый, Вы писали:

ТЗИ>Используй указатели на члены класса, а не трюки с offset'ов. У меня в одном проекте подобная задача — это, фактически, рефлексия для C++.

я бы рад, но, к сожалению, это невозможно в моей задаче.
Re: расмоложение мемберов класса в памяти
От: szag  
Дата: 14.06.10 19:43
Оценка:
Пока придумал вот такую конструкцию и проверил на всех смещениях от 1 до 16 — работает.
struct iAligment
{
    char e;
    double f;
};

struct CurrentAligment
{
    enum
    {
        Value = offsetof(iAligment, f) - offsetof(iAligment, e)
    };
};


template<class T, std::size_t val = sizeof(T), std::size_t a = CurrentAligment::Value>
struct MyAlign
{
    enum
    {
        Result = ((val / a) * a == val) ? 0 : (((val / a) + 1) * a) - val
    };
};

// использование
class ClassName
{
//.....
    std::size_t GetSize() const
    {                                    
        return sizeof( ClassName ) + MyAlign<ClassName>::Result;
    }
//.....
};

Может кто-то покритикует или предложет что-то получше?
Re[2]: расмоложение мемберов класса в памяти
От: Seigram  
Дата: 14.06.10 23:50
Оценка:
Здравствуйте, szag, Вы писали:

S>Пока придумал вот такую конструкцию и проверил на всех смещениях от 1 до 16 — работает.

S>Может кто-то покритикует или предложет что-то получше?

Упрощать
struct CurrentAligment
{
    enum
    {
        Value = __alignof(struct {})
    };
};


Ты на каких компиляторах пробовал самый 1-й вариант, — без workarounds?
Re[3]: расмоложение мемберов класса в памяти
От: szag  
Дата: 15.06.10 05:57
Оценка:
Здравствуйте, Seigram, Вы писали:

S>Ты на каких компиляторах пробовал самый 1-й вариант, — без workarounds?


проверял в VS2010, для чистоты эксперимента надо бы еще проверить в gcc. __alignof(), насколько я понимаю, Microsoft specific оператор, т.е. гцц про него ничего не знает, так? Если так то этот вариант не подходит.
Re[4]: расмоложение мемберов класса в памяти
От: Seigram  
Дата: 15.06.10 12:41
Оценка:
Здравствуйте, szag, Вы писали:

S>Здравствуйте, Seigram, Вы писали:


S>>Ты на каких компиляторах пробовал самый 1-й вариант, — без workarounds?


S>проверял в VS2010, для чистоты эксперимента надо бы еще проверить в gcc. __alignof(), насколько я понимаю, Microsoft specific оператор, т.е. гцц про него ничего не знает, так? Если так то этот вариант не подходит.


Верно, верно. Выравние это прямо — тема. Вот ссылка к примеру:
см. последние 2 абзаца. т.е. все сильно зависит от компилятора(padding спереду или сзаду), вообще как на ум компилятору взбредет. Потом все перестает работатть при #pragma pack(push,N) — формулы не справились и т.д.
И поэтому, для БЕЗОПАСНОСТИ кода надо отказаться от твоей затеи. Перейти к указателям на члены. Можно сколько угодно колдовать с offsetof() но тебе придется написать кучу define's чтобы обеспечить приемственность. Опять же никто не гарантирует "подставы".
Лучьше обработай шефа на тему "безопасность и красота" требует жертв, и перепиши lib'ку. Дальше ведь работать и расширять её проще будет. Капитан Очевидность подсказывает — что делать софт гибче, удобнее и надежнее надо не каменным топором, а современными инструментами.
Re[5]: расмоложение мемберов класса в памяти
От: szag  
Дата: 15.06.10 14:20
Оценка:
Здравствуйте, Seigram, Вы писали:

S> Верно, верно. Выравние это прямо — тема. Вот ссылка к примеру:

S>см. последние 2 абзаца. т.е. все сильно зависит от компилятора(padding спереду или сзаду), вообще как на ум компилятору взбредет. Потом все перестает работатть при #pragma pack(push,N) — формулы не справились и т.д.

вероятность использования подобных конструкций конкретно в моей ситуации крайне мала.

S> И поэтому, для БЕЗОПАСНОСТИ кода надо отказаться от твоей затеи. Перейти к указателям на члены. Можно сколько угодно колдовать с offsetof() но тебе придется написать кучу define's чтобы обеспечить приемственность. Опять же никто не гарантирует "подставы".

S> Лучьше обработай шефа на тему "безопасность и красота" требует жертв, и перепиши lib'ку. Дальше ведь работать и расширять её проще будет. Капитан Очевидность подсказывает — что делать софт гибче, удобнее и надежнее надо не каменным топором, а современными инструментами.

Вы все правильно говорите и даже переписать либу не проблема — проблема чтобы не пострадал клиентский код. А как переписать либу, чтобы сделать её гарантированно безопасной и при этом не пострадал клиентский код я не знаю.
К примеру, при текущей реализации я даже не могу обратиться из конструктора класса к одному из его мемберов, так как в конструкторе просто нет такой информации — она генерируется во время компиляции.
Вот упрощенный пример пользовательского кода:
TABLE(sysUser, ALLOWDOMAIN(true), 
    INT(id, 50, INITVALUE(100))
    STRING(name, 100, 60, INITVALUE(L"TestDefaultString"))
    DATE(birthday, 10, EDITABLE(false))
    TIME(localtime, 31)
    BOOL(IsOk, 25)
    DOUBLE(mydouble, 45)
    )

А вот пример использования:
sysUser su;
su.name = L"tralaylay";
su.id = 500;
int maxLen = su.name.GetMaxLength();

и такого кода тьма тьмущая. Для каждого поля, в приведенном выше примере, генерируется куча кода, реально создается класс, который наследуется от базового, который шаблонный с кучей специализаций... Если подытожить, то я с вами согласен на 100%, но что делать в данной конкретной ситуации?
Re[2]: расмоложение мемберов класса в памяти
От: MShura  
Дата: 15.06.10 15:13
Оценка:
S>Может кто-то покритикует или предложет что-то получше?

Что будет если есть подряд 4 или 8 элементов по 1 байту?
Re[3]: расмоложение мемберов класса в памяти
От: szag  
Дата: 15.06.10 15:22
Оценка:
Здравствуйте, MShura, Вы писали:


S>>Может кто-то покритикует или предложет что-то получше?


MS>Что будет если есть подряд 4 или 8 элементов по 1 байту?

Не будет. Как я писал выше, все поля гарантированно известных типом и не могут быть меньше нескольких десятков байт — это классы с виртуальными функциями и мемберами.
Re[4]: расмоложение мемберов класса в памяти
От: MShura  
Дата: 15.06.10 15:46
Оценка:
MS>>Что будет если есть подряд 4 или 8 элементов по 1 байту?
S>Не будет. Как я писал выше, все поля гарантированно известных типом и не могут быть меньше нескольких десятков байт — это классы с виртуальными функциями и мемберами.

Как тогда трактовать предложение

Пока придумал вот такую конструкцию и проверил на всех смещениях от 1 до 16 — работает.


Как Вы проверили смещение 1 байт?
Re[5]: расмоложение мемберов класса в памяти
От: szag  
Дата: 15.06.10 16:01
Оценка:
Здравствуйте, MShura, Вы писали:

MS>>>Что будет если есть подряд 4 или 8 элементов по 1 байту?

S>>Не будет. Как я писал выше, все поля гарантированно известных типом и не могут быть меньше нескольких десятков байт — это классы с виртуальными функциями и мемберами.

MS>Как тогда трактовать предложение


MS>

MS>Пока придумал вот такую конструкцию и проверил на всех смещениях от 1 до 16 — работает.


MS>Как Вы проверили смещение 1 байт?

проверял 2 вещи:
struct CurrentAligment
{
    enum
    {
        Value = offsetof(iAligment, f) - offsetof(iAligment, e) // это значение
    };
};

и работоспособность проекта при выставленном смещении в настройках проекта.
Re[6]: расмоложение мемберов класса в памяти
От: Кодт Россия  
Дата: 15.06.10 16:13
Оценка:
Здравствуйте, szag, Вы писали:

S>Вы все правильно говорите и даже переписать либу не проблема — проблема чтобы не пострадал клиентский код. А как переписать либу, чтобы сделать её гарантированно безопасной и при этом не пострадал клиентский код я не знаю.

S>К примеру, при текущей реализации я даже не могу обратиться из конструктора класса к одному из его мемберов, так как в конструкторе просто нет такой информации — она генерируется во время компиляции.
S>Вот упрощенный пример пользовательского кода:
S>
S>TABLE(sysUser, ALLOWDOMAIN(true), 
S>    INT(id, 50, INITVALUE(100))
S>    STRING(name, 100, 60, INITVALUE(L"TestDefaultString"))
S>    DATE(birthday, 10, EDITABLE(false))
S>    TIME(localtime, 31)
S>    BOOL(IsOk, 25)
S>    DOUBLE(mydouble, 45)
S>    )
S>

S>А вот пример использования:
S>
S>sysUser su;
S>su.name = L"tralaylay";
S>su.id = 500;
S>int maxLen = su.name.GetMaxLength();
S>


То есть, макрос TABLE(sysUser,.....) превращается в
struct sysUser : SomeBase
{
  Field<int,50> id;
  Field<string,100> name;
  .....

  static FieldInfo listOfFields[];
  sysUser();
};

sysUser::sysUser()
: SomeBase(????)
, id(100)
, name(L"TestDefaultString")
, .....
{}

FieldInfo sysUser::listOfFields[] = {
  { "id",   sizeof(Field<int,50>) },
  { "name", sizeof(Field<string,100>) },
  .....
}

Правильно?
Тогда кто мешает в список полей добавить не только их размеры, но и смещения (а ещё лучше — указатели-на-члены)?
Будет там что-то вида
  { "id",   sizeof(Field<int,50>),     _offsetof(sysUser,id)   },
  { "name", sizeof(Field<string,100>), _offsetof(sysUser,name) },
  .....
Перекуём баги на фичи!
Re[7]: расмоложение мемберов класса в памяти
От: szag  
Дата: 15.06.10 16:37
Оценка:
Здравствуйте, Кодт, Вы писали:
К>То есть, макрос TABLE(sysUser,.....) превращается в
К>
К>struct sysUser : SomeBase
К>{
К>  Field<int,50> id;
К>  Field<string,100> name;
К>  .....

К>  static FieldInfo listOfFields[];
К>  sysUser();
К>};

К>sysUser::sysUser()
К>: SomeBase(????)
К>, id(100)
К>, name(L"TestDefaultString")
К>, .....
К>{}

К>FieldInfo sysUser::listOfFields[] = {
К>  { "id",   sizeof(Field<int,50>) },
К>  { "name", sizeof(Field<string,100>) },
К>  .....
К>}
К>

К>Правильно?
К>Тогда кто мешает в список полей добавить не только их размеры, но и смещения (а ещё лучше — указатели-на-члены)?
К>Будет там что-то вида
К>
К>  { "id",   sizeof(Field<int,50>),     _offsetof(sysUser,id)   },
К>  { "name", sizeof(Field<string,100>), _offsetof(sysUser,name) },
К>  .....
К>


1. слишком много изменений в клиентском коде;
2. клиентский код станет писать сложнее, появится много зависимостей, как то, за был прописать поле в табличку или еще чего.

макросы эти были придуманы для того, чтобы сделать жизнь енд юзера проще, хорошо или плохо это было сделано вопрос другой, но сейчас клиентский код менять никто не даст, к тому же, он работает уже более 3-х лет, т.е. отлажен... и работает в разных организациях, которые не обрадуются такому апдейту сервера, при котором надо переписывать код...
Re[6]: расмоложение мемберов класса в памяти
От: MShura  
Дата: 15.06.10 17:10
Оценка:
MS>>Как тогда трактовать предложение

MS>>

MS>>Пока придумал вот такую конструкцию и проверил на всех смещениях от 1 до 16 — работает.


MS>>Как Вы проверили смещение 1 байт?

S>проверял 2 вещи:
S>
S>struct CurrentAligment
S>{
S>    enum
S>    {
S>        Value = offsetof(iAligment, f) - offsetof(iAligment, e) // это значение
S>    };
S>};
S>

S>и работоспособность проекта при выставленном смещении в настройках проекта.

Это называется, как Вы сами заметили в названии структуры, выравнивание, а не смещение.
Re[8]: расмоложение мемберов класса в памяти
От: Кодт Россия  
Дата: 15.06.10 17:11
Оценка:
Здравствуйте, szag, Вы писали:

S>1. слишком много изменений в клиентском коде;

S>2. клиентский код станет писать сложнее, появится много зависимостей, как то, за был прописать поле в табличку или еще чего.

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


Почему изменения в клиентском коде? Я спрашивал
1) макрос разворачивается в подобный код?
2) что мешает изменить макрос, чтобы он генерировал таблицу не только с размерами, но и смещениями?

Или же клиентский код уже скомпилирован, и его нельзя трогать?
То есть, — всё, что у нас есть, это таблица с отдельными полями. И по этой таблице надо восстановить лэяут структуры.

Тогда нужно для каждого поля знать не только его размер, но и его выравнивание. Это, по счастью, — свойство типа, а не свойство отдельного члена.
Логика более-менее простая:
int roundUp(int size, int align) { return (size+align-1)%align; }

int overall_tail = sizeof(Base); // текущий хвост структуры
int overall_align = _alignof(Base); // выравнивание структуры
int overall_size = min(1, roundUp(overall_tail, overall_align); // размер структуры

.....
// для каждого очередного поля

int field_size, field_align; // размер и выравнивание текущего поля
assert(field_align > 0);
assert(field_size % field_align == 0);

int field_offset = roundUp(overall_tail, field_align);

overall_align = max(overall_align, field_align);
overall_tail = field_offset + field_size;
overall_size = roundUp(overall_tail, overall_align);

Всё, что надо — это добавить в интерфейс рядом с GetSize() ещё и GetAlign().

Но, всё же, с таблицей смещений будет проще и надёжнее.
Перекуём баги на фичи!
Re[9]: расмоложение мемберов класса в памяти
От: Seigram  
Дата: 15.06.10 17:36
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, szag, Вы писали:

[skipped]
К>Но, всё же, с таблицей смещений будет проще и надёжнее.

Я бы иначе написал это и думаю угодил бы запросу szag.
Собственно сообразить как компилятор и что размещает не сложно зная типы полей
Примерно так, -для простоты у меня шаблон, а у szag можно сделать табличку для замены sizeof(std::remove_all_extents<T>::type):


template <class T> int next_offset(int &offset, int &total_size) {
  int x = offset;
  size_t size = sizeof(T), mask = sizeof(std::remove_all_extents<T>::type) - 1,
      trusted_offset = offset;
  if (offset & mask) {
    trusted_offset = offset = (offset + mask) & ~mask;
  }
  offset += size; total_size += offset - x;
  return trusted_offset;
}

финальный размер тоже подровнять
total_size = (total_size + (compiler_opt_align -1)) &~(compiler_opt_align -1)

естественно в начале
int offset=0, total_size =0



p.s.. проверено на POD's включая поля растущие как typedef pod_type type_name[N]
Re[7]: расмоложение мемберов класса в памяти
От: szag  
Дата: 15.06.10 20:57
Оценка:
Здравствуйте, MShura, Вы писали:

MS>Это называется, как Вы сами заметили в названии структуры, выравнивание, а не смещение.

да, извините, опечатался — имел ввиду именно выравнивание.
Re[9]: расмоложение мемберов класса в памяти
От: szag  
Дата: 15.06.10 21:11
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, szag, Вы писали:


S>>1. слишком много изменений в клиентском коде;

S>>2. клиентский код станет писать сложнее, появится много зависимостей, как то, за был прописать поле в табличку или еще чего.

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


К>Почему изменения в клиентском коде? Я спрашивал

К>1) макрос разворачивается в подобный код?
К>2) что мешает изменить макрос, чтобы он генерировал таблицу не только с размерами, но и смещениями?

1) Видимо не правильно Вас понял. макрос внутри менять можно, нельзя менять клиентский код, т.е. если поменять макрос и клиентский код при этом перекомпилируется и гарантированно будет работать — то проблем нет
2) наверное только незнание того как это сделать

вот пример макроса, который генерит сам класс (выкинул кучу всего что мешает пониманию)
#define TABLE(name, meta, fields)                               \
class name : public ORMtableBase                                    \
{                                                                   \
public:                                                             \
                                                                    \
    meta                                                            \
                                                                    \
                                                                    \
    fields                                                          \
                                                                    \
private:                                                            \
    static FieldsList FieldsMap;                                    \
};                                                                  \
ORMtableBase::FieldsList name::FieldsMap;                           \


т.е. видно, что филды сюда приходят ввиде последовательно идущих макросов, так как количество их не известно, может быть одно а может и 100. meta так же поток макросов.

как я и писал выше, филды достаточно стожные классы, которые генерируются макросами, а дальше шаблонами.
Re: расмоложение мемберов класса в памяти
От: Seigram  
Дата: 15.06.10 21:13
Оценка:
Здравствуйте, szag, Вы писали:

S>есть задача обращаться к полям класса по их имени, т.е. зная строку. Это строка, приходит, парсится потом собственно идет само обращение.

[skipped]
S>P.S. Все эти извращения потому, что в месте использования нет информации о конечном типе, а есть только интерфейс.

В принципе решил я это для CodeGear2010 и MSVC2010. 1-й признать порадовал, — в обратном смысле слова
Фукция считает offset, для упрощения оформлена шаблоном
template <class T> int nextP(int &offset, int &total_size, bool &realign) {
  int prev_offset = offset;
  typedef std::remove_all_extents<T>::type U;
  size_t size = sizeof(T), mask = sizeof(U) - 1, trusted_offset = offset;
  int c = std::tr1::is_class<U>::value ? alignof(T) : 0;
  if (c) mask = c - 1;
  if (!realign && (offset & mask)) {
    trusted_offset = offset = (offset + mask) & ~mask;
  }
 #ifdef __CODEGEARC__
  if (c) realign = true; // maybe its code_gear bug
 #endif
  offset += size; total_size += offset - prev_offset;
  return trusted_offset;
}

Собственно для MSVC "костыль" c realign можно отрезать напрочь.
Для [b]szag использовать таблицы вместо tr1 и std::remove_all_extents[/b]
Проверял я на таких структурах:

typedef double DD[2];
typedef float FD[3];
typedef float XD[13];
struct boo {
  float k;
  double r;
  DD r1;
  char ccc[17];
};
struct goo {
  DD r1;
  short t;
  char uu[61];
  std::map <std::string, int > maps;
};
struct F {
  char a;
  short g;
  XD u;
  boo oob;
  long long b;
  std::vector <DD> vecs;
  double c;
  DD fg;
  goo oob2;
  FD fl;
};


Собственно проверка(MSVC):
  int offset =0, size=0; bool realm=0;
  int offs1=offsetof(F,a),    xoffs1=nextP <char> (offset,size,realm);
  int offs2=offsetof(F,g),    xoffs2=nextP <short> (offset,size,realm);
  int offs3=offsetof(F,u),    xoffs3=nextP <XD> (offset,size,realm);
  int offs4=offsetof(F,oob),  xoffs4=nextP <boo> (offset,size,realm);
  int offs5=offsetof(F,b),  xoffs5=nextP <long long> (offset,size,realm);
  int offs6=offsetof(F,vecs),  xoffs6=nextP <std::vector <DD> > (offset,size,realm);
  int offs7=offsetof(F,c),  xoffs7=nextP <double> (offset,size,realm);
  int offs8=offsetof(F,fg),  xoffs8=nextP <DD> (offset,size,realm);
  int offs9=offsetof(F,oob2),  xoffs9=nextP <goo> (offset,size,realm);
  int offs10=offsetof(F,fl),  xoffs10=nextP <FD> (offset,size,realm);  
  int opt = __alignof(F);
  unsigned S0=(size+(opt-1))&~(opt-1);
  unsigned S1=sizeof(F);

Проверка от CodeGear

  Memo1->Lines->Add(offsetof(F,a));
  Memo1->Lines->Add(offsetof(F,g));
  Memo1->Lines->Add(offsetof(F,u));
  Memo1->Lines->Add(offsetof(F,oob));
  Memo1->Lines->Add(offsetof(F,b));
  Memo1->Lines->Add(offsetof(F,vecs));
  Memo1->Lines->Add(offsetof(F,c));
  Memo1->Lines->Add(offsetof(F,fg));
  Memo1->Lines->Add(offsetof(F,oob2));
  Memo1->Lines->Add(offsetof(F,fl));
  Memo1->Lines->Add(sizeof(F));
  int offset = 0, size = 0; bool realign = false;
  Memo1->Lines->Add(nextP<char>(offset,size,realign));
  Memo1->Lines->Add(nextP<short>(offset,size,realign));
  Memo1->Lines->Add(nextP<XD>(offset,size,realign));
  Memo1->Lines->Add(nextP<boo>(offset,size,realign));
  Memo1->Lines->Add(nextP<long long>(offset,size,realign));
  Memo1->Lines->Add(nextP<vector<DD> > (offset,size,realign));
  Memo1->Lines->Add(nextP<double>(offset,size,realign));
  Memo1->Lines->Add(nextP<DD>(offset,size,realign));
  Memo1->Lines->Add(nextP<goo>(offset,size,realign));
  Memo1->Lines->Add(nextP<FD>(offset,size,realign));
  int opt = alignof(struct{});
  Memo1->Lines->Add((size+(opt-1))&~(opt-1));
Re[10]: расмоложение мемберов класса в памяти
От: Кодт Россия  
Дата: 15.06.10 22:51
Оценка:
Здравствуйте, szag, Вы писали:

К>>1) макрос разворачивается в подобный код?

К>>2) что мешает изменить макрос, чтобы он генерировал таблицу не только с размерами, но и смещениями?

S>1) Видимо не правильно Вас понял. макрос внутри менять можно, нельзя менять клиентский код, т.е. если поменять макрос и клиентский код при этом перекомпилируется и гарантированно будет работать — то проблем нет

S>2) наверное только незнание того как это сделать

Буст-препроцессор может творить чудеса...
Вообще же, каркас макроса выглядит так
#define TABLE(name,meta,fields) \
  struct name : ORMtableBase { \
    meta \
    MEMBERS(fields) \
  }; \
  static ORMField name::FieldsArray[] = { METADATA(name,fields) }; \
  static const int name::FieldsCount = _countof(name::FieldsArray); \
  //endmacro

Дальше MEMBERS развёртывает макро-цепочку, превращая её в объявления полей, а METADATA — в метаданные (размеры, смещения).
Завтра попробую на BOOST/PP родить рабочий пример.
Перекуём баги на фичи!
Re[10]: расмоложение мемберов класса в памяти
От: Кодт Россия  
Дата: 15.06.10 22:57
Оценка:
Здравствуйте, Seigram, Вы писали:

S>Я бы иначе написал это и думаю угодил бы запросу szag.

S>Собственно сообразить как компилятор и что размещает не сложно зная типы полей

В момент итерирования типы полей неизвестны. Поля представлены интерфейсом IORMField*, у которого есть GetSize().
По одному только размеру судить о выравнивании сложно: char[8], int[2] и double имеют одинаковый размер и разное выравнивание
Поэтому придётся добавить в интерфейс GetAlign().
Ну а дальше — в реализациях — операторы sizeof и __alignof (или его рукодельная замена, не суть).
Перекуём баги на фичи!
Re[11]: расмоложение мемберов класса в памяти
От: szag  
Дата: 16.06.10 06:07
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, szag, Вы писали:


К>>>1) макрос разворачивается в подобный код?

К>>>2) что мешает изменить макрос, чтобы он генерировал таблицу не только с размерами, но и смещениями?

S>>1) Видимо не правильно Вас понял. макрос внутри менять можно, нельзя менять клиентский код, т.е. если поменять макрос и клиентский код при этом перекомпилируется и гарантированно будет работать — то проблем нет

S>>2) наверное только незнание того как это сделать

К>Буст-препроцессор может творить чудеса...

К>Вообще же, каркас макроса выглядит так
К>
К>#define TABLE(name,meta,fields) \
К>  struct name : ORMtableBase { \
К>    meta \
К>    MEMBERS(fields) \
К>  }; \
К>  static ORMField name::FieldsArray[] = { METADATA(name,fields) }; \
К>  static const int name::FieldsCount = _countof(name::FieldsArray); \
К>  //endmacro
К>

К>Дальше MEMBERS развёртывает макро-цепочку, превращая её в объявления полей, а METADATA — в метаданные (размеры, смещения).
К>Завтра попробую на BOOST/PP родить рабочий пример.

не уверен что правильно понял вашу идею.
fields представляет из себя поток дефайнов, вида:
INT(id, 50, INITVALUE(100))
STRING(name, 100, 60, INITVALUE(L"TestDefaultString"))
DATE(birthday, 10)
TIME(localtime, 31)
BOOL(IsOk, 25)
DOUBLE(pisun, 45)

каждый дефайн вызывает другой дефайн, который формирует класс делает следующее:
#define FIELD(TypeID, RealType, name, captionID, ...)            \
class RealType ## _ ## name : public ORMfield<TypeID, RealType>      \
{                                                                    \
public:                                                              \
    explicit RealType ## _ ## name () : ORMfield(#name , captionID)  \
    {                                                                \
        InitValue(FieldValue);                                       \
    }                                                                \
                                                                     \
   // куча кода опущена                                                                  \
                                                                     \
    std::size_t GetSize() const                                      \
    {                                                                \
        return sizeof( RealType ## _ ## name ) +                     \
            MyAlign<RealType ## _ ## name>::Result;                  \
    }                                                                \
                                                                     \
    __VA_ARGS__                                                      \
                                                                     \
};                                                                   \
                                                                     \
RealType ## _ ## name name;

т.е основная задача этого дефайна:
1. сформировать класс, с конструктором не принимающим параметры
2. перекрыть некоторые виртуальные функции, как то GetSize и некоторые функции в __VA_SRGS__, если пользователь указал что-то вроде EDITABLE(false). дальше создается поле по этому классу.

в общем-то функция GetSize сейчас уже включает в себя выравнивание поля.

Дальше вся эта хитрая конструкция обрабатывается кодом см. мой первый пост.
Re[10]: расположение мемберов класса в памяти
От: szag  
Дата: 16.06.10 06:09
Оценка:
Здравствуйте, Seigram, Вы писали:

S>Здравствуйте, Кодт, Вы писали:


К>>Здравствуйте, szag, Вы писали:

S>[skipped]
К>>Но, всё же, с таблицей смещений будет проще и надёжнее.

S>Я бы иначе написал это и думаю угодил бы запросу szag.

S>Собственно сообразить как компилятор и что размещает не сложно зная типы полей
S>Примерно так, -для простоты у меня шаблон, а у szag можно сделать табличку для замены sizeof(std::remove_all_extents<T>::type):


S>
S>template <class T> int next_offset(int &offset, int &total_size) {
S>  int x = offset;
S>  size_t size = sizeof(T), mask = sizeof(std::remove_all_extents<T>::type) - 1,
S>      trusted_offset = offset;
S>  if (offset & mask) {
S>    trusted_offset = offset = (offset + mask) & ~mask;
S>  }
S>  offset += size; total_size += offset - x;
S>  return trusted_offset;
S>}

S>финальный размер тоже подровнять
S>total_size = (total_size + (compiler_opt_align -1)) &~(compiler_opt_align -1)
S>

S>естественно в начале
S>
S>int offset=0, total_size =0
S>



S>p.s.. проверено на POD's включая поля растущие как typedef pod_type type_name[N]


Извините, но я что-то с первого раза не понял, чем ваша конструкция принципиально отличается от того варианта который сейчас сделал я — sizeof() + Aligment, см. посты ниже.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.