C++ 在旧代码中创建基于类型的标识号,更改最少
我正在维护一个非常古老(20多年)且相当大(15KLOC)的库,其中包含各种类型的对象,这些对象当前由整数标识。这就产生了一个问题,就是给定整数,我不知道它应该识别哪种类型的对象。在编译时这样做真的很好 我提出的解决方案是创建一个ID模板,然后为各种类型的对象ID创建typedefs <>我意识到我必须添加第三个PARAM到模板中,因为我认为两个完全不同的标识符可以具有相同的基础类型和范围。p> < >我发现C++没有考虑< /P>C++ 在旧代码中创建基于类型的标识号,更改最少,c++,linux,templates,gcc,maintenance,C++,Linux,Templates,Gcc,Maintenance,我正在维护一个非常古老(20多年)且相当大(15KLOC)的库,其中包含各种类型的对象,这些对象当前由整数标识。这就产生了一个问题,就是给定整数,我不知道它应该识别哪种类型的对象。在编译时这样做真的很好 我提出的解决方案是创建一个ID模板,然后为各种类型的对象ID创建typedefs 我意识到我必须添加第三个PARAM到模板中,因为我认为两个完全不同的标识符可以具有相同的基础类型和范围。p> < >我发现C++没有考虑< /P> typedef int X; typedef int Y; 完全
typedef int X;
typedef int Y;
完全不同的类型
这个解决方案是:-
A) 合理(我知道它是有效的)
B) 有没有其他简单的方法可以做到这一点——管理层害怕高LOC变化
仅使用示例运算符简化解
#include <iostream>
// Horrible old definition of current code
class OldObjectA
{
public:
int ident_; // int identifier
int uniq_; // another int identifier unique to OldObjectA's only
};
class OldObjectB
{
public:
int ident_;
int next_; // int of another OldObjectB ident_
int uniq_; // another int identifier unique to OldObjectB's only
int dq_; // int of yet anothera OldObjectB ident_
int com_; // int of ident_ of a OldObjectA
int ld_; // int of ident_ of a OldObjectC
};
class OldObjectC
{
public:
int indent_;
int next_; // int of another OldObjectC ident_
int com_; // int of ident_ of a OldObjectA
};
enum Type { TypeA, TypeAU, TypeB, TypeBU, TypeC };
template<class T, T maxval, Type type>
class ID
{
public:
friend bool operator==(const ID<T, maxval, type> &lhs, const ID<T, maxval, type> &rhs)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
return true;
}
};
typedef ID<int, 42, TypeA> ID_A;
typedef ID<int, 42, TypeAU> ID_UniqA;
typedef ID<int, 42, TypeB> ID_B;
typedef ID<int, 42, TypeBU> ID_UniqB;
typedef ID<int, 100, TypeC> ID_C;
// What I was thinking of doing
class NewObjectA
{
public:
ID_A ident_; // int identifier
ID_UniqA uniq_; // another int identifer
};
class NewObjectB
{
public:
ID_B ident_;
ID_B next_; // int of another OldObjectB ident_
ID_UniqB uniq_; // another int
ID_B dq_; // int of yet anothera OldObjectB ident_
ID_A com_; // int of ident_ of a OldObjectA
ID_C ld_; // int of ident_ of a OldObjectC
};
class NewObjectC
{
public:
ID_C indent_;
ID_C next_; // int of another OldObjectC ident_
ID_A com_; // int of ident_ of a OldObjectA
};
int main(int argc, char *argv[])
{
std::cout << "================================================================================\n";
ID_A a,a2;
ID_UniqA au,au2;
ID_B b,b2;
ID_UniqB bu,bu2;
ID_C c,c2;
a==a2;
au==au2;
b==b2;
bu==bu2;
c==c2;
// wanted and expected compile time fails
// a=au;
// a=b;
// a=bu;
// a=c;
// au=b;
// au=bu;
// au=c;
// b=bu;
// b=c;
std::cout << "================================================================================\n";
return 0;
}
#包括
//当前代码的旧定义太可怕了
类OldObjectA
{
公众:
int ident;//int标识符
int uniq;//另一个仅对OldObjectA唯一的int标识符
};
类OldObjectB
{
公众:
内部识别;
int next;//另一个OldObjectB标识的int_
int uniq;//另一个仅对OldObjectB唯一的int标识符
int dq_;//另一个旧对象标识的int_
int com;//旧对象的标识的int
int ld;//OldObjectC的标识的int
};
类OldObjectC
{
公众:
int缩进;
int next;//另一个旧对象标识的int_
int com;//旧对象的标识的int
};
枚举类型{TypeA,TypeAU,TypeB,TypeBU,TypeC};
模板
类ID
{
公众:
友元布尔运算符==(常量ID和lhs、常量ID和rhs)
{
std::cout添加模板参数以区分其他相同类型的想法是合理的。这是一种非常有用的技术,每隔一段时间就会出现一次。最近,我在定义度量类型时使用了类似的技术(即km、l、s等)
您至少可以对现有内容进行一种简化。枚举不是必需的。您可以在类型的ID定义中使用类型本身
template<class T, T maxval, class tag>
struct ID {
};
template<class T, T maxval, class tag>
bool operator==(ID<T, maxval, tag> lhs, ID<T, maxval, tag> rhs)
{
return true;
}
typedef ID<int, 42, class NewObjectA> ID_A;
typedef ID<int, 42, class NewObjectB> ID_B;
struct NewObjectA {
ID_A id;
};
struct NewObjectB {
ID_B id;
};
void f()
{
ID_A id_a;
ID_B id_b;
id_a == id_a;
id_b == id_b;
//id_a == id_b; // won't compile as expected
}
模板
结构ID{
};
模板
布尔运算符==(ID左侧,ID右侧)
{
返回true;
}
typedef ID_A;
typedef ID_B;
结构NewObjectA{
身份证;
};
结构NewObjectB{
ID_B ID;
};
void f()
{
身份证;
ID_B ID_B;
id_a==id_a;
id_b==id_b;
//id\u a==id\u b;//无法按预期编译
}
这样做的好处是不需要在一个地方创建程序中所有类型的全局列表。如果需要按照继承层次结构允许的转换来处理ID,那么使用类型本身也可以使事情变得更简单。例如,ObjectC是ObjectA,因此ID_C可以转换为ID_a
我发现添加这种东西(我正在做的测量工作也很相似)这种渐进式的方法通常是可行的。每次你需要接触一段代码时,都会在本地引入一些改进,并在进行更多更改之前确认它们按预期工作。如果你认为你已经发现了一个bug并改变了程序行为,那么测试这些更改尤其重要。尝试一次性改变一切相反,e往往会带来很多痛苦