Нужна инициализация избранных полей структуры в зависимости от значения Id. Делается это во время определения массива этих структур.
// в реальном коде она сложнее :)struct S
{
int Id;
union
{
struct
{
char c;
} Id1;
struct
{
__int64 i64;
} Id2;
};
};
Т.е. при значении Id=1 нужно инициализировать переменную с, при Id=2 — i64, а при Id=0 вообще ничего не инициализировать!
Проблема
1) union дает доступ только к первой переменной/структуре
2) Если я инициализирую только Id, то остальное компилятор обнуляет, а это лишний код
Я поискал по форуму и понял, что нужно использовать конструкторы. Но объекты я пока не изучал, т.к. тема мутная, синтаксис объектов мутный, в форуме в каждом втором сообщении мутные цитаты из стандарта... Может кто-нибудь мне привести конкретный пример? Нужно с чего-то начать.
По второй проблеме наткнулся в этом форуме на мутную цитату из стандарта
— if T is a reference type, no initialization is performed.
Что есть reference type? Может запихнуть его первым полем union-а, что бы избежать ненужного обнуления?
Здравствуйте, CoolCmd, Вы писали:
CC>Т.е. при значении Id=1 нужно инициализировать переменную с, при Id=2 — i64, а при Id=0 вообще ничего не инициализировать!
А чем инициализировать?
CC>Что есть reference type? Может запихнуть его первым полем union-а, что бы избежать ненужного обнуления?
Это тебе не нужно.
Ты лучше объясни что за массив? Если статический или глобальный, то время на инициализацию нулями не тратится, если временная переменная в функции (автоматический массив), т о тратится.
Но тогда можешь написать конструктор у своей структуры.
Но я не понимаю, зачем тебе её вообще инициализировать чем-то?
По умолчанию (если не будешь определять конструктор) твоя структура в автоматическом массиве вообще никак инициализироваться не будет...
КОнструктор пишут так:
struct S
{
S() // Имя конструктора совпадает с именем структуры
{
// Этот конструктор, например, вообще ничего не делает
// А если раскомментарить следующую строку, то будет инициализировать Id в ноль
// Id = 0;
}int Id;
union
{
struct
{
char c;
} Id1;
struct
{
__int64 i64;
} Id2;
};
};
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Сложная compile-time инициализация структуры
От:
Аноним
Дата:
25.09.07 21:37
Оценка:
Здравствуйте, Erop, Вы писали:
E>А чем инициализировать?
Значениями, рассчитываемыми в функции. Я неудачно название темы выбрал , не compile-time, а run-time, но во время определения массива.
Т.е. сейчас это делается примерно так:
S HugeArray[] ={{1, byteLocalVariable1 + 37}, {2, &LocalVariable2}, {0}};
В итоге вместо байта сохраняется 8 байт (все валится в ULONG_PTR), плюс лишние нули для последнего элемента.
E>Ты лучше объясни что за массив? Если статический или глобальный, то время на инициализацию нулями не тратится, если временная переменная в функции (автоматический массив), т о тратится.
Локальный массив в функции. Я в дебагере смотрел, что там нагенерилось.
E>Но тогда можешь написать конструктор у своей структуры. E>Но я не понимаю, зачем тебе её вообще инициализировать чем-то?
Эта байда передается драйверу, который ее обрабатывает. Если не определить массив, то придется вызывать драйвер для каждой структуры, а переход из r3 в r0 и обратно в NT занимает много времени.
E>По умолчанию (если не будешь определять конструктор) твоя структура в автоматическом массиве вообще никак инициализироваться не будет... E>КОнструктор пишут так: E>
struct S
E>{
E> S() // Имя конструктора совпадает с именем структуры
E> {
E> // Этот конструктор, например, вообще ничего не делает
E> // А если раскомментарить следующую строку, то будет инициализировать Id в ноль
E> // Id = 0;
E> }
E>};
Не, мне нужна примерно вот такая возможность:
S HugeArray[] ={{Id:=1, c:=byteLocalVariable1 + 37}, {Id:=2, i64:=&LocalVariable2}, {Id:=0}};
:= я сейчас от балды придумал
Re[3]: Сложная compile-time инициализация структуры
Если массив действительно Huge, то вряд ли ты его будешь инициализировать агрегатом — тогда и сишный код тоже будет huge
К тому же по-любому программа в каждый элемент что-то пишет, тратит на это время и инструкции.
Так что можешь совершенно спокойно использовать конструкторы.
Впрочем, если структура описана в API драйвера, то навесить на неё конструктор так просто не получится.
Тут есть 3 возможности:
— сделать класс (с нетривиальным конструктором) с идентичным layout'ом, ==> layout массива объектов этого типа будет таким же, как и у массива оригинальных структур
— — наследование
— — рукоделие
#pragma pack(push,1)
struct CS : public S // если компилятор gcc, то ещё укажи атрибут выравнивания
{
CS() { Id=0; }
CS(char x) { Id=1; c=x; }
CS(int64 x) { Id=2; i64=x; }
};
#pragma pack(pop)
.....
void foo()
{
CS arr[] = { CS('x'), CS(1LL<<48), CS() };
}
— написать make-функции, конструирующие оригинальные структуры
// можно перегрузку, а можно разноимённые функции
S makeSv() { S s; s.Id=0; return s; }
S makeSc(char x) { S s; s.Id=1; s.c=x; return s; }
S makeSi(__int64 x) { S s; s.Id=2; s.i64=x; return s; }
.....
void foo()
{
S arr[] = { makeSc('x'), makeSi(1LL<<48), makeSv(); }
.....
}
— ну и, наконец, банально вручную заполнять
void foo()
{
S arr[3] = {};
initS(arr[0], 'x'); // это макрос или функция void initS(S& dst, .....)
initS(arr[1], 1LL<<48);
initS(arr[2]);
}
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[4]: Сложная compile-time инициализация структуры
К>Если массив действительно Huge, то вряд ли ты его будешь инициализировать агрегатом — тогда и сишный код тоже будет huge
Что значит "инициализировать агрегатом"? Сейчас массив заполняется с помощью вложенных макросов.
К>К тому же по-любому программа в каждый элемент что-то пишет, тратит на это время и инструкции.
Ну разумеется, чудес не бывает.
К>Так что можешь совершенно спокойно использовать конструкторы.
Насколько я понимаю, машинный код конструкторов будет почти идентичен моему сегодняшнему варианту, но с возможностью задать нужные поля.
К>Впрочем, если структура описана в API драйвера, то навесить на неё конструктор так просто не получится.
Драйвер мой, могу делать все что захочу.
К>- — наследование
Была у меня мысль наплодить наследничков, но как их в массив запихнуть я точно не знаю. И как быть с их размерами, ведь они получатся разными....
К>
К>#pragma pack(push,1)
К>struct CS : public S // если компилятор gcc, то ещё укажи атрибут выравнивания
К>{
К> CS() { Id=0; }
К> CS(char x) { Id=1; c=x; }
К> CS(int64 x) { Id=2; i64=x; }
К>};
К>#pragma pack(pop)
Интересный вариант, если дополнить макросами. А с push(1) проблем на x64 системах не будет?
К>- написать make-функции, конструирующие оригинальные структуры К>
К>// можно перегрузку, а можно разноимённые функции
К>S makeSv() { S s; s.Id=0; return s; }
К>S makeSc(char x) { S s; s.Id=1; s.c=x; return s; }
К>S makeSi(__int64 x) { S s; s.Id=2; s.i64=x; return s; }
К>.....
К>void foo()
К>{
К> S arr[] = { makeSc('x'), makeSi(1LL<<48), makeSv(); }
К> .....
К>}
К>
Выглядит просто шикарно! Но каким образом передается структура в return s? Где она создается? Если в куче, то вариант отпадает.
К>
К>void foo()
К>{
К> S arr[3] = {};
К> initS(arr[0], 'x'); // это макрос или функция void initS(S& dst, .....)
К> initS(arr[1], 1LL<<48);
К> initS(arr[2]);
К>}
К>
Количество элементов массива подсчитать сложно, а иначе я бы наплодил функций и пробмлем не было.
Спасибо за варианты, приду домой, буду шаманить. Кстати я здесь на форуме видел еще один вариант конструктора, что-то вроде этого (по памяти пишу)
class B: _x(x) _y(y) {}.
простите, я убил небо
Re[4]: Сложная compile-time инициализация структуры
Здравствуйте, CoolCmd, Вы писали:
CC>Добрый!
CC>Нужна инициализация избранных полей структуры в зависимости от значения Id. Делается это во время определения массива этих структур. CC>
CC>// в реальном коде она сложнее :)
CC>struct S
CC>{
CC> int Id;
CC> union
CC> {
CC> struct
CC> {
CC> char c;
CC> } Id1;
CC> struct
CC> {
CC> __int64 i64;
CC> } Id2;
CC> };
CC>};
CC>
CC>Т.е. при значении Id=1 нужно инициализировать переменную с, при Id=2 — i64, а при Id=0 вообще ничего не инициализировать!
А что если Id не в диапазоне от 0 до 2 ??
struct S
{
int Id;
union
{
struct
{
char c;
} Id1;
struct
{
__int64 i64;
} Id2;
};
// коструктор
S(int new_id) : Id(new_id)
{
switch (id)
{
case 1: Id1.c= 0; break;
case 2: Id2.i64= 0; break;
}
}
};
int main()
{
S s= 1, o= 2;
}
Re[5]: Сложная compile-time инициализация структуры
Здравствуйте, CoolCmd, Вы писали:
К>>Если массив действительно Huge, то вряд ли ты его будешь инициализировать агрегатом — тогда и сишный код тоже будет huge CC>Что значит "инициализировать агрегатом"? Сейчас массив заполняется с помощью вложенных макросов.
Это форма записи с фигурными скобками.
К>>Впрочем, если структура описана в API драйвера, то навесить на неё конструктор так просто не получится. CC>Драйвер мой, могу делать все что захочу.
Ну если тебе не жалко заточить API драйвера под C++ — то пожалуйста.
К>>- — наследование CC>Была у меня мысль наплодить наследничков, но как их в массив запихнуть я точно не знаю. И как быть с их размерами, ведь они получатся разными....
Можно сформировать массив указателей на объекты — а сами объекты разместить где-то рядом. (Естественно, драйвер должен быть готов к такому).
Можно сериализовать объекты (в массив байтов, или в структуру, поля которой — разнотипные объекты, или ещё каким способом).
CC>Интересный вариант, если дополнить макросами. А с push(1) проблем на x64 системах не будет?
А какие проблемы? Базовый подобъект сохраняет свой layout, это просто гарантия того, что в наследник не будут напиханы хвостовые пробелы по воле компилятора.
Скажем, если sizeof(S)=3, то без выравнивания может получиться sizeof(CS)=4. А с выравниванием — sizeof(CS)==sizeof(S).
К>>- написать make-функции, конструирующие оригинальные структуры К>>
К>>// можно перегрузку, а можно разноимённые функции
К>>S makeSv() { S s; s.Id=0; return s; }
К>>S makeSc(char x) { S s; s.Id=1; s.c=x; return s; }
К>>S makeSi(__int64 x) { S s; s.Id=2; s.i64=x; return s; }
К>>.....
К>>void foo()
К>>{
К>> S arr[] = { makeSc('x'), makeSi(1LL<<48), makeSv(); }
К>> .....
К>>}
К>>
CC>Выглядит просто шикарно! Но каким образом передается структура в return s? Где она создается? Если в куче, то вариант отпадает.
Учите матчасть, дорогой Ватсон! Всё создаётся исключительно на стеке. (Между прочим, это легальный сишный код, а не исключительно С++ный).
Более того, если компилятор догадается сделать оптимизацию NRVO, то адреса внутренних переменных s совпадут с адресами элементов массива.
В случае, если функции inline, таких шансов больше, но и если они extern, то тоже вполне может получиться.
Так что скрещивай сию методу со своими макросами, и будет тебе щасте.
CC>Спасибо за варианты, приду домой, буду шаманить. Кстати я здесь на форуме видел еще один вариант конструктора, что-то вроде этого (по памяти пишу) CC>
CC>class B: _x(x) _y(y) {}.
CC>
Это не С++ Что-то напутал по памяти.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[5]: Сложная compile-time инициализация структуры
Здравствуйте, CoolCmd, Вы писали:
CC>И еще один вопрос: можно конструктор сделать inline?
Точно так же, как и обычную функцию.
class X
{
public:
X();
X(int);
X(char) { } // inlineinline X(double) { } // inline, можно было ключевое слово не писать
};
inline X::X() { }
// в недрах .cpp
X::X(int) { } // не inline
Причём если ты не объявил конструктор копирования, оператор присваивания, деструктор, а то и дефолтный конструктор — все они будут созданы компилятором и проинлайнены.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[2]: Сложная compile-time инициализация структуры
Здравствуйте, Кодт, Вы писали:
К>>>- — наследование CC>>Была у меня мысль наплодить наследничков, но как их в массив запихнуть я точно не знаю. И как быть с их размерами, ведь они получатся разными.... К>Можно сформировать массив указателей на объекты — а сами объекты разместить где-то рядом. (Естественно, драйвер должен быть готов к такому).
Пока я не представляю, как разместить "где-то рядом".
К>>>- написать make-функции, конструирующие оригинальные структуры CC>>Выглядит просто шикарно! Но каким образом передается структура в return s? Где она создается? Если в куче, то вариант отпадает. К>Учите матчасть, дорогой Ватсон! Всё создаётся исключительно на стеке. (Между прочим, это легальный сишный код, а не исключительно С++ный). К>Более того, если компилятор догадается сделать оптимизацию NRVO, то адреса внутренних переменных s совпадут с адресами элементов массива. К>В случае, если функции inline, таких шансов больше, но и если они extern, то тоже вполне может получиться.
Мне даже в голову не приходило так делать, ведь это теоретически не эффективно. Сейчас проверил на примере, так и оказалось.
enum OPERATION_ID {OP_ID_0, OP_ID_1, OP_ID_2};
struct S
{
public:
OPERATION_ID Id;
union
{
struct
{
int *Param1;
int Param2;
} Id1Parameters;
struct
{
char Param1;
} Id2Parameters;
};
};
inline S Operation0()
{
S s;
s.Id = OP_ID_0;
return s;
}
inline S Operation1(int *p1, int p2)
{
S s;
s.Id = OP_ID_1;
s.Id1Parameters.Param1 = p1;
s.Id1Parameters.Param2 = p2;
return s;
}
inline S Operation2(char p1)
{
S s;
s.Id = OP_ID_2;
s.Id2Parameters.Param1 = p1;
return s;
}
void TestFunc()
{
int n;
S arr[] =
{
Operation0(),
Operation1(&n, 10),
Operation2('a')
};
}
Совсем другое дело, ничего лишнего!
Но этот вариант неудобный, т.к. нужный конструктор выбирается на основе передаваемых параметром, а это легко может привести к путанице (не в этом примере). Так что придется писать макросы с приведением параметром, но и в этом варианте нет уверенности...
Сдесь мне пришел в голову другой вариант: в базовом классе оставить данные, и наплодить наследников с нужными конструкторами.
enum OPERATION_ID {OP_ID_0, OP_ID_1, OP_ID_2};
struct S
{
public:
OPERATION_ID Id;
union
{
struct
{
int *Param1;
int Param2;
} Id1Parameters;
struct
{
char Param1;
} Id2Parameters;
};
};
struct Operation0 : public S
{
public:
Operation0() {
Id = OP_ID_0;
};
};
struct Operation1 : public S
{
public:
Operation1(int *p1, int p2) {
Id = OP_ID_1;
Id1Parameters.Param1 = p1;
Id1Parameters.Param2 = p2;
};
};
struct Operation2 : public S
{
public:
Operation2(char p1)
{
Id = OP_ID_2;
Id2Parameters.Param1 = p1;
};
};
void TestFunc()
{
int n;
S arr[] =
{
Operation0(),
Operation1(&n, 10),
Operation2('a')
};
}
Результат оказался в точности как в первом примере, т.е. с лишними инструкциями копирования.
Почему в данном случае нет оптимизации? Компилятор тупо не делает сравнение на размер объектов?
Можно это как-то исправить? Может я наследование как-то неверно сделал.
И еще непонятка. Вот на этот вариант:
struct Operation2 : public S
{
public:
Operation2(char p1) : Id(OP_ID_2) {
//Id = OP_ID_2;
Id2Parameters.Param1 = p1;
};
};
компилятор ругается
error C2614: 'Operation2' : illegal member initialization: 'Id' is not a base or member
простите, я убил небо
Re[7]: Сложная compile-time инициализация структуры
Здравствуйте, CoolCmd, Вы писали:
CC>И еще непонятка. Вот на этот вариант: CC>
CC> Operation2(char p1) : Id(OP_ID_2) {
CC>
CC>компилятор ругается CC>
error C2614: 'Operation2' : illegal member initialization: 'Id' is not a base or member
Ты можешь инициализировать только свои базы и поля!!! Поля базы должна инициализировать база!!!
Есть, кстати, ещё и такой путь:
struct S {
// тут данные
S& SetOp0() // возвращает ссылку на следующий объект в векторе
{
// тут инициализируешь как надо и return this[1];
}
S& SetOp1( int ) // возвращает ссылку на следующий объект в векторе
{
// тут инициализируешь как надо и return this[1];
}
S& SetOp2( char ) // возвращает ссылку на следующий объект в векторе
{
// тут инициализируешь как надо и return this[1];
}
};
Ещё есть путь через продвинутые шаблоны. Типа создаёшь объект-инициализатор, в котором в самом типе хранится какой элемент вектора чем инициализировать, а в объекте параметры, а потом натравливаеь его на инициализируемый вектор. Пример использования может быть каким-то таким:
struct S {
// тут данные
// Операция 0enum Op0_t { Op0 };
S( Op0_t ) { InitOp0(); }
// Операция 1enum Op1_t { Op1 };
S( Op1_t, int i ) { InitOp1( i ); }
// Операция 2enum Op2_t { Op2 };
S( Op2_t, char ch ) { InitOp2( ch ); }
};
// Ну и теперь пользуемся понаписанными чудесами:
S vec[] = { S( S::Op1, 5 ), S( S::Op2, 'A' + 4 ), S( S::Op0 ), S( S::Op1, 18 ) };
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: Сложная compile-time инициализация структуры
Здравствуйте, CoolCmd, Вы писали:
К>>Более того, если компилятор догадается сделать оптимизацию NRVO, то адреса внутренних переменных s совпадут с адресами элементов массива. К>>В случае, если функции inline, таких шансов больше, но и если они extern, то тоже вполне может получиться. CC>Мне даже в голову не приходило так делать, ведь это теоретически не эффективно. Сейчас проверил на примере, так и оказалось.
В релизе? Ну, значит, не судьба.
CC>После этого я попробовал вариант с нормальным конструктором. Вот что получилось: CC>Совсем другое дело, ничего лишнего! CC>Но этот вариант неудобный, т.к. нужный конструктор выбирается на основе передаваемых параметром, а это легко может привести к путанице (не в этом примере). Так что придется писать макросы с приведением параметром, но и в этом варианте нет уверенности...
Это делается элементарно: если ты не уверен в том, что сигнатуры конструкторов выберутся правильно на основе "существенных" параметров, — добавь несущественные:
template<OPERATION_ID Id> struct id2type // самое главное - вот это
{
operator OPERATION_ID () const { return Id; } // а это так, сахарку насыпал
};
#define TAG(Id) (id2type<Id>())
struct S
{
.....
explicit S( id2type<OP_ID_0> tag ) : Id(tag) { }
explicit S( id2type<OP_ID_1> tag, int* p1, int p2 ) : Id(tag) { Id1Parameters.Param1 = p1; Id1Parameters.Param2 = p2; }
explicit S( id2type<OP_ID_2> tag, char p1 ) : Id(tag) { Id2Parameters.Param1 = p1; }
};
#define S_0() S(TAG(OP_ID_0))
#define S_1(p1,p2) S(TAG(OP_ID_1),p1,p2)
#define S_2(p1) S(TAG(OP_ID_2),p1)
Если окажется, что передача тэга по значению стоит слишком дорого, попробуй заменить его на указатель
CC>Сдесь мне пришел в голову другой вариант: в базовом классе оставить данные, и наплодить наследников с нужными конструкторами. CC>Результат оказался в точности как в первом примере, т.е. с лишними инструкциями копирования. CC>Почему в данном случае нет оптимизации? Компилятор тупо не делает сравнение на размер объектов? CC>Можно это как-то исправить? Может я наследование как-то неверно сделал.
Потому что конструкторы наследников не шибко отличаются от make-функций. Да ещё и — из-за наследования — никакие оптимизации (кроме инлайна, естественно) оказываются невозможными.
Если в первом случае компилятор просто не додумался до NRVO, то в этом ему просто запрещено его делать.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[8]: Сложная compile-time инициализация структуры
Здравствуйте, Кодт, Вы писали:
К>Это делается элементарно: если ты не уверен в том, что сигнатуры конструкторов выберутся правильно на основе "существенных" параметров, — добавь несущественные:
Ого, я так пока и не понял, как работает этот "элементарный" код. До операторов и шаблонов пока не добрался.
К>Если окажется, что передача тэга по значению стоит слишком дорого, попробуй заменить его на указатель
Да нет, все замечательно , доп. машинного кода вообще не добавилось, как и в варианте Erop-а.
Вот думаю, какой оставить. Наверное Erop-а, т.к. он более понятный.
CC>>Результат оказался в точности как в первом примере, т.е. с лишними инструкциями копирования. CC>>Почему в данном случае нет оптимизации? Компилятор тупо не делает сравнение на размер объектов? CC>>Можно это как-то исправить? Может я наследование как-то неверно сделал. К>Потому что конструкторы наследников не шибко отличаются от make-функций. Да ещё и — из-за наследования — никакие оптимизации (кроме инлайна, естественно) оказываются невозможными. К>Если в первом случае компилятор просто не додумался до NRVO, то в этом ему просто запрещено его делать.
А почему запрещено? Если нет ничего виртуального и размеры объектов равны, то ИМХО можно смело оптимизировать, ведь порядок данных в объекте при наследовании не меняется.
простите, я убил небо
Re[8]: Сложная compile-time инициализация структуры
Здравствуйте, Erop, Вы писали:
CC>>И еще непонятка. Вот на этот вариант: CC>>
CC>> Operation2(char p1) : Id(OP_ID_2) {
CC>>
E>Ты можешь инициализировать только свои базы и поля!!! Поля базы должна инициализировать база!!!
Ясно. А зачем вообще нужны инициализации вида : Id(OP_ID_2) { если тоже самое можно сделать обычным присваиванием в конструкторе без всякого гемороя? У меня в справке и книге об этом ничего нет. Кстати, вариант : Id1Parameters.Param1(p1) { тоже не жрет — на точку ругается.
E> S& SetOp2( char ) // возвращает ссылку на следующий объект в векторе E> { E> // тут инициализируешь как надо и E> return this[1]; E> } E>S& endOfInit = vec[0].SetOp1( 5 ).SetOp2( 'a' ).SetOp0().SetOp1( 8 ); E>assert( &endOfInit == vec + lengthof( vec ) );[/c]
Вроде понятно, только this[1] хакерскими приемчиками попахивает, нет?
E>Правда мне лично больше всего нравится таки инициализация без извращений, в таком вот виде:
Мне тоже, но неудобно, да и конструкторы в этом случае не нужны — обычной структуры хватит.
E>Ну или, как крайний вариант, такая штука:
Не понял, почему крайний? Простой, понятный и рабочий вариант. Наверное его и оставлю. Большое спасибо.
E>
struct S {
E> // тут данные
E> // Операция 0
E> enum Op0_t { Op0 };
E> S( Op0_t ) { InitOp0(); }
E>// Ну и теперь пользуемся понаписанными чудесами:
E>S vec[] = { S( S::Op1, 5 ), S( S::Op2, 'A' + 4 ), S( S::Op0 ), S( S::Op1, 18 ) };
E>
простите, я убил небо
Re[9]: Сложная compile-time инициализация структуры
Здравствуйте, CoolCmd, Вы писали:
E>>Ты можешь инициализировать только свои базы и поля!!! Поля базы должна инициализировать база!!! CC>Ясно. А зачем вообще нужны инициализации вида : Id(OP_ID_2) { если тоже самое можно сделать обычным присваиванием в конструкторе без всякого гемороя? У меня в справке и книге об этом ничего нет.
Некоторые поля и базы нельзя инициализировать по умолчанию...
Например ссылку или открытый файл или ещё чего...
CC>Кстати, вариант : Id1Parameters.Param1(p1) { тоже не жрет — на точку ругается.
1) Я так понял, что имя класса, а не объекта. ТОгда надо писать ::
2) Так тоже нельзя, можно так:
Id1ParametersOp1() : Id1Parameters( p1 ) {};
Где Id1Parameters( p1 ) -- это вызов конструктора базы, который, в свою очередь устроен так:
Id1Parameters( int p ) : Param1( p ) {};
CC>Вроде понятно, только this[1] хакерскими приемчиками попахивает, нет?
Пока ты инициализируешь элементы вектора всё абсолютно законно...
E>>Правда мне лично больше всего нравится таки инициализация без извращений, в таком вот виде:
CC>Мне тоже, но неудобно, да и конструкторы в этом случае не нужны — обычной структуры хватит.
Да, конструкторы не нужны, код оптиальный, структура POD и без всяких извратов. Да и понятно всё, кстати...
E>>Ну или, как крайний вариант, такая штука: CC>Не понял, почему крайний? Простой, понятный и рабочий вариант. Наверное его и оставлю. Большое спасибо.
Хозяин -- барин
Обращайся
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: Сложная compile-time инициализация структуры
Здравствуйте, CoolCmd, Вы писали:
К>>Если в первом случае компилятор просто не додумался до NRVO, то в этом ему просто запрещено его делать. CC>А почему запрещено? Если нет ничего виртуального и размеры объектов равны, то ИМХО можно смело оптимизировать, ведь порядок данных в объекте при наследовании не меняется.
Ну вообще-то надо бы ещё и копировать. Но ненужное копирование компилятор мог бы и выбрасывать, конечно, но он мог бы и в варианте с функциями-мэйкерами
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: Сложная compile-time инициализация структуры
Здравствуйте, CoolCmd, Вы писали:
К>>Это делается элементарно: если ты не уверен в том, что сигнатуры конструкторов выберутся правильно на основе "существенных" параметров, — добавь несущественные: CC>Ого, я так пока и не понял, как работает этот "элементарный" код. До операторов и шаблонов пока не добрался.
Да всё просто: теперь все конструкторы различаются не только по количеству аргументов, но и по типам. Причём так, что невозможно сделать случайное приведение.
struct S
{
explicit S( char c ) : Id(OP_ID_Char) { ..... }
explicit S( int i ) : Id(OP_ID_Int) { ..... }
};
void foo()
{
S arr[] =
{
S( 'x' ), // char
S( 'x'+1 ), // int
};
}
Чтобы не лепить типы-тэги вручную, и был сделан шаблон id2type. Плюс этого шаблона в том, что из него можно извлекать значение тэга — это уменьшает риск очепяток
struct S
{
explicit S( id2type<OP_ID_0> tag ) : Id(OP_ID_1) {}
.....
}