在类声明中使用typedefining迭代器的问题

时间:2016-06-23 14:11:14

标签: c++ c++11 stl iterator incomplete-type

我正在编写遗留代码,编写得很糟糕,只能在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

2 个答案:

答案 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_ptrtypedef 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:抱歉我的英语不好。