标头中的枚举会导致过多的重新编译

Gri*_*ngo 5 c c++

John Lakos 将此问题称为编译时耦合的潜在根源(他的简介中的图 0-3):

我面临的问题是编译了太多文件,因为对单个枚举存在物理依赖性。

我有一个带有枚举定义的标头:

// version.h
enum Version {
    v1 = 1,
    v2, v3, v4, v5, ... v100
};
Run Code Online (Sandbox Code Playgroud)

这被数百个文件使用。每个文件定义一类对象,必须使用该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
    }
}
Run Code Online (Sandbox Code Playgroud)

// 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,正如您所看到的,一旦发生ObjectA更改,我们就必须v100Version. 因此,type*.cpp即使只有真正需要该条目的文件,所有文件都将read()ObjectA编译v100

如何反转对枚举的依赖,对客户端(即type*.cpp)代码进行最小的更改,以便仅编译必要的 .c 文件?

这是我想到的一种可能的解决方案,但我需要一个更好的解决方案:

我想我可以将枚举放在 .cpp 文件中,并int使用相应枚举成员的值公开 s:

//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
Run Code Online (Sandbox Code Playgroud)

Version以某种方式为类型创建别名

//version.h
typedef const int Version;
Run Code Online (Sandbox Code Playgroud)

并只引入每次需要的 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
    }
}
Run Code Online (Sandbox Code Playgroud)

但我认为这看起来是一个非常糟糕的解决方案,可以追溯到标题前的时间

use*_*249 0

您可以将枚举作为配置数据放置在单独的 .cfg 文件中,然后其他每个源文件都会读取该配置文件。

那么当配置文件改变时,不需要重新编译。

所有其他文件读取/解析配置文件。

这是处理此类信息的经典方法。

注意:配置文件不会包含枚举,而是包含某些格式化数据。