我正在编写遗留代码,编写得很糟糕,只能在Microsoft Visual Studios和Visual C ++编译器中编译。由于构建时错误,GCC,G ++或Clang都无法编译代码。我已将问题缩小到以下类声明,该声明在类声明中实例化STL
的{{1}}容器:
class type
我想知道在保留代码结构的同时重构此代码段的最佳方法是什么。例如,我试图使用指针类型(即#include <map>
#include <set>
#include <iomanip>
#include <string>
#include <cmath>
#include <iterator>
#include <unordered_map>
#include <bits/unique_ptr.h>
#define HASH_MAP unordered_map
using namespace std;
namespace XYZ {
class abc {
public:
typedef HASH_MAP<double, abc> MAP; // This is the problem ?
typedef MAP::iterator Iterator;
typedef MAP::const_iterator ConstIterator;
typedef pair<double, abc> Pair;
bool less(abc::Pair& a, abc::Pair& b) { return a.first < b.first; }
public:
abc() {}
~abc() { }
};
}
)进行MAP
定义。但是,此更改适用于GCC编译器,因为,我正在更改为指针类型,我将不得不挖掘深入到代码库并修改大部分代码库,因为这个类在其他相关代码中起着关键作用。
所以我想知道是否有替代方法可以解决此问题,而不需要对原始代码库进行重大更改。我正在考虑使typedef HASH_MAP<double, XYZ*> MAP
类相似。
以下是编译器错误:
friend
答案 0 :(得分:3)
问题是(无论出于什么原因 - 地狱,它只是一个typedef!)与迭代器。如果你从类代码中移出它们,以便在定义时完成类定义,它就会编译(使用g ++)。也许应该将Iterator
重命名为MAP_Iterator
等。我可以想象客户端代码中所需的更改是可管理的
编辑:在您发表评论之后,我有了将迭代器typedef放在名为abc
的类(原始类名)中以保持与客户端代码的源兼容性的想法。实际的类定义被移动到客户端代码不需要显式使用的基类。该映射包含基类的对象,在存储或检索真实abc
时涉及切片和反向转换。可能无法对映射中的值保持abc
引用,但下面的简单基于值的示例(使用迭代器)可以正常工作。源代码中有一些注释。
#include <unordered_map>
#include <iostream>
using namespace std;
// The "original" abc
class abcBase
{
public:
typedef unordered_map<double, abcBase> MAP; // This is the problem ?
typedef pair<double, abcBase> Pair;
bool less(abcBase::Pair& a, abcBase::Pair& b) { return a.first < b.first; }
string tag;
public:
abcBase(string t): tag(t){}
abcBase() = default;
~abcBase() { }
};
// The abc presented to the users for source compatibility.
// There is a conversion
// from base to derived via constructor.
//
// Note that a MAP
// holds abcBase objects, not abc objects! We need to convert them
// when we store and when we read.
// Conversion derived -> base is via slicing
// (which does not do any harm as long as we do not define
// data members in derived).
class abc: public abcBase
{
public:
// conversion constructor
abc(const abcBase &b): abcBase(b){}
abc(string t): abcBase(t){}
abc() = default;
typedef MAP::iterator Iterator;
typedef MAP::const_iterator ConstIterator;
};
int main()
{
abc::MAP m;
abc a("a"),b("b"),c("c");
m[1.0] = a; // conversion abc -> abcBase ...
m[2.0] = b;
m[3.0] = c;
a = m[1.0]; // conversion abcBase -> abc via ctor
for( abc::Iterator i = m.begin(); i != m.end(); ++i)
{
cout << "key: " << i->first << ", val: " << i->second.tag << endl;
}
return 0;
}
答案 1 :(得分:0)
您正在使用std::unordered_map
,因此您正在使用C ++ 11。
因此,我认为使用std::unique_ptr
(typedef HASH_MAP<double, std::unique_ptr<XYZ>> MAP
代替typedef HASH_MAP<double, XYZ*> MAP
)可以帮助您减少以下修改。
例如,以下代码编译
#include <utility>
#include <memory>
#include <unordered_map>
using namespace std;
#define HASH_MAP unordered_map
namespace abc {
class XYZ {
private:
int _test;
public:
typedef HASH_MAP<double, std::unique_ptr<XYZ>> MAP; // This is the problem ?
typedef MAP::iterator Iterator;
typedef MAP::const_iterator ConstIterator;
typedef pair<double, std::unique_ptr<XYZ>> Pair;
bool less(XYZ::Pair& a, XYZ::Pair& b) { return a.first < b.first; }
public:
XYZ():_test(0) {}
~XYZ() { }
// Some function definitions
};
};
int main ()
{
return 0;
}
显然我假设您的命名空间为abc
,而您的班级名称为XYZ
;你不能在地图中放置命名空间。
p.s:抱歉我的英语不好。