c++ - 在类声明中使用类型定义迭代器的问题

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

<分区>

我正在处理一段遗留代码,该代码编写得很糟糕,只能在 Microsoft Visual Studios 和 Visual C++ 编译器中编译。由于构建时错误,GCC、G++ 或 Clang 都无法编译代码。我已将问题缩小到以下实例化 STL 的类声明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使用指针类型定义(即 typedef HASH_MAP<double, XYZ*> MAP)但是,此更改适用于 GCC 编译器,因为我正在更改为指针类型,因此我将不得不深入研究代码库并将大部分代码库修改为此类在其他依赖代码中起着关键作用。

所以我想知道是否有解决此问题的替代方案,不需要对原始代码库进行重大更改。我正在考虑制作 friend类相似。

编译错误如下:

    In file included from /usr/include/c++/4.8/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/4.8/bits/stl_tree.h:61,
                 from /usr/include/c++/4.8/map:60,
                 from /home/user/work/wxy.h:4,
                 from /home/user/work/abc.h:4,
                 from /home/user/work/abc.cpp:1:
/usr/include/c++/4.8/bits/stl_pair.h: In instantiation of ‘struct std::pair<const double, XYZ::abc>’:
/usr/include/c++/4.8/type_traits:615:28:   required from ‘struct std::__is_destructible_impl<std::pair<const double, XYZ::abc> >’
/usr/include/c++/4.8/type_traits:637:12:   required from ‘struct std::__is_destructible_safe<std::pair<const double, XYZ::abc>, false, false>’
/usr/include/c++/4.8/type_traits:652:12:   required from ‘struct std::is_destructible<std::pair<const double, XYZ::abc> >’
/usr/include/c++/4.8/type_traits:116:12:   required from ‘struct std::__and_<std::is_destructible<std::pair<const double, XYZ::abc> >, std::__is_direct_constructible_impl<std::pair<const double, XYZ::abc>, const std::pair<const double, XYZ::abc>&> >’
/usr/include/c++/4.8/type_traits:817:12:   required from ‘struct std::__is_direct_constructible_new_safe<std::pair<const double, XYZ::abc>, const std::pair<const double, XYZ::abc>&>’
/usr/include/c++/4.8/type_traits:895:12:   [ skipping 4 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/c++/4.8/type_traits:968:12:   required from ‘struct std::__is_copy_constructible_impl<std::pair<const double, XYZ::abc>, false>’
/usr/include/c++/4.8/type_traits:974:12:   required from ‘struct std::is_copy_constructible<std::pair<const double, XYZ::abc> >’
/usr/include/c++/4.8/bits/alloc_traits.h:540:12:   required from ‘struct std::__is_copy_insertable<std::allocator<std::pair<const double, XYZ::abc> > >’
/usr/include/c++/4.8/bits/alloc_traits.h:560:63:   required by substitution of ‘template<class _Alloc> using __check_copy_constructible = std::__allow_copy_cons<std::__is_copy_insertable<_Alloc>::value> [with _Alloc = std::allocator<std::pair<const double, XYZ::abc> >]’
/usr/include/c++/4.8/bits/unordered_map.h:97:11:   required from ‘class std::unordered_map<double, XYZ::abc>’
/home/user/work/abc.h:27:20:   required from here
/usr/include/c++/4.8/bits/stl_pair.h:102:11: error: ‘std::pair<_T1, _T2>::second’ has incomplete type
       _T2 second;                /// @c second is a copy of the second object
           ^
In file included from /home/user/work/abc.cpp:1:0:
/home/user/work/abc.h:24:11: error: forward declaration of ‘class XYZ::abc’
     class abc {
           ^

最佳答案

问题是(无论出于何种原因——该死,它只是一个类型定义!)与迭代器有关。如果您将它们移出您的类代码,以便类定义在它们的定义点完成,它会编译(使用 g++)。也许应该将 Iterator 重命名为 MAP_Iterator 或类似名称。我可以想象客户端代码中所需的更改是可管理的

编辑:在您发表评论后,我想到将迭代器 typedef 放在一个名为 abc(原始类名)的类中,以保持与客户端代码的源代码兼容性。实际的类定义被移动到客户端代码不需要显式使用的基类。该映射包含基类的对象,在存储或检索真实的 abc 时涉及切片和反向转换。可能无法在 map 中保留对值的 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;
}       

关于c++ - 在类声明中使用类型定义迭代器的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37994122/

相关文章:

c++ - 定义一个内部有结构的 map

c++ - 转置二维动态矩阵

c++ - QT:错误 [在 ")"标记之前应为 "*",并且 MainWindow 未命名类型]

c++ - boost::program_options - 如何处理 INI 文件中具有相同名称的多个部分

c++ - std::enable_if 有条件地编译一个成员函数

c++ - const 和 constexpr 最终会是一回事吗?

java - JNI 包装器从 C++ 读取列表并返回到 JAVA

C++ Maya - 从帧和子帧获取网格顶点

c++ - 编译器错误 : looser throw specifier for destuctor

design-patterns - 为什么STL中没有 "Iterable"接口(interface)?