Джон Лакос ссылается на эту проблему как на коварный источник компиляция-время (рисунок 0-3, в его Введении):
Проблема, с которой я сталкиваюсь, заключается в том, что слишком много файлов скомпилировано, потому что существует физическая зависимость от одного перечисления.
У меня есть заголовок с определением перечисления:
// version.h
enum Version {
v1 = 1,
v2, v3, v4, v5, ... v100
};
и это используется сотнями файлов.
Каждый файл определяет класс объектов, которые нужно читать с диска,
используя функцию read()
. Version
используется для определения способа считывания данных.
Каждый раз, когда вводится новый класс или член класса, новая запись добавляется к перечислению
// typeA.cpp
#include "version.h"
void read (FILE *f, ObjectA *p, Version v)
{
read_float(f, &p->x);
read_float(f, &p->y);
if (v >= v100) {
read_float(f, &p->z); // after v100 ObjectA becomes a 3D
}
}
и
// typeB.cpp
#include "version.h"
void read (FILE *f, ObjectB *p, Version v)
{
read_float (f, &p->mass);
if (v >= v30) {
read_float (f, &p->velocity);
}
if (v >= v50) {
read_color (f, &p->color);
}
}
Теперь, как вы можете видеть, после изменений ObjectA
мы должны ввести новую запись (скажем v100
) в Version
. Следовательно, все файлы type*.cpp
будут скомпилированы, хотя только read()
of ObjectA
действительно нуждается в записи v100
.
Как я могу инвертировать зависимость от перечисления с минимальными изменениями в клиенте (т.е. type*.cpp
), так что компилируются только необходимые файлы .c?
Вот возможное решение, о котором я думал, но мне нужно лучшее:
Я думал, что могу поместить enum в .cpp файл и выставить int
со значениями соответствующих членов перечисления:
//version.cpp
enum eVersion {
ev1 = 1,
ev2, ev3, ev4, ev5, ... ev100
};
const int v1 = ev1;
const int v2 = ev2;
....
const int v100 = ev100; // introduce a new global int for every new entry in the enum
сделать псевдоним для типа Version
как-то
//version.h
typedef const int Version;
и вводить только значения const int, которые необходимы каждый раз:
// typeA.cpp
#include "version.h"
extern Version v100; ///// *** will be resolved at link time
void read (FILE *f, ObjectA *p, Version v)
{
read_float(f, &p->x);
read_float(f, &p->y);
if (v >= v100) {
read_float(f, &p->z); // after v100 ObjectA becomes a 3D
}
}
но я думаю, что это выглядит очень плохое решение, которое датируется временем предварительного заголовка