STL映射到自身?

时间:2009-09-10 05:24:36

标签: c++ stl map containers

我想创建一个std::map,其中包含std::vector个迭代器,以实现一个简单的基于邻接列表的图形结构。

但是,类型声明让我感到难过:看起来你需要整个地图类型定义来获取所述地图的迭代器类型,如下所示:

map< int, Something >::iterator MyMap_it;  // what should Something be?
map< int, vector<MyMap_it> > MyMap_t;

是否有某种部分地图迭代器类型我只能使用键类型来获取,所以我可以声明完整的地图?

4 个答案:

答案 0 :(得分:14)

您可以使用新类型的前向声明。

class MapItContainers;
typedef map<int, MapItContainers>::iterator MyMap_it;

class MapItContainers
{
public:
 vector<MyMap_it> vec;
};

通过这种间接,编译器应该让你逃脱它。 它不是那么漂亮,但说实话,我认为你不能轻易打破自我引用。

答案 1 :(得分:5)

不太难看,考虑到......

这适用于GCC 4.0.1并且在Comeau严格模式下编译良好。

解析和推迟模板定义,直到它们被实例化。编译器甚至没有看到rec_map_iterator是什么,直到它创建一个,到那时它知道如何这样做; v)。

template< class key >
struct rec_map;

template< class key >
struct rec_map_iterator : rec_map< key >::iterator {
    rec_map_iterator( typename rec_map< key >::iterator i)
    : rec_map< key >::iterator(i) {}
};

template< class key >
struct rec_map : map< key, vector< rec_map_iterator< key > > > {};

这是我使用的测试程序。

#include <iostream>
#include <map>
#include <vector>

using namespace std;

template< class key >
struct rec_map;

template< class key >
struct rec_map_iterator : rec_map< key >::iterator {
    rec_map_iterator( typename rec_map< key >::iterator i)
    : rec_map< key >::iterator(i) {}
};

template< class key >
struct rec_map : map< key, vector< rec_map_iterator< key > > > {};

int main( int argc, char ** argv ) {
    rec_map< int > my_map;

    my_map[4];
    my_map[6].push_back( my_map.begin() );

    cerr << my_map[6].front()->first << endl;

    return 0;
}

答案 2 :(得分:2)

我不喜欢在我之前的回答中从容器派生,所以这里有另一种选择:

template< class key >
struct rec_map_gen {
    struct i;
    typedef map< key, vector< i > > t;
    struct i : t::iterator {
        i( typename t::iterator v )
        : t::iterator(v) {}
    };
};

现在您必须使用rec_map_gen<int>::trec_map_gen<int>::t::iterator等,但您也可以访问所有std::map的构造函数。太糟糕了,C ++不允许对模板进行模板化。

使用派生的迭代器类型应该没问题。例如,您仍然可以从此结构的元素初始化反向迭代器。

答案 3 :(得分:2)

除了Potatoswatter的回答之外,如果你不介意多次引用整个模板化地图类型,你只需要对迭代器进行子类化,不需要任何预先声明:

InkCanvas

然后使用完整类型:

 private void Canvas_PointerPressed(object sender, PointerRoutedEventArgs e)
    {
        // Get information about the pointer location.
        PointerPoint pt = e.GetCurrentPoint(inkCanvas);
        m_PreviousContactPoint = pt.Position;
        m_Point2 = new Point(0, 0);
        m_Point1 = pt.Position;
        // Accept input only from a pen or mouse with the left button pressed.
        PointerDeviceType pointerDevType = e.Pointer.PointerDeviceType;
        if (pointerDevType == PointerDeviceType.Pen ||
            pointerDevType == PointerDeviceType.Mouse && pt.Properties.IsLeftButtonPressed)
        {
            e.Handled = true;
            IsPressed = true;
        }
        else if (pointerDevType == PointerDeviceType.Touch)
        {
            // Process touch input
        }
    }

    private void Canvas_PointerMoved(object sender, PointerRoutedEventArgs e)
    {

        if (IsPressed)
        {
            PointerPoint pt = e.GetCurrentPoint(inkCanvas);

            var currentContactPt = pt.Position;
            var x1 = m_PreviousContactPoint.X;
            var y1 = m_PreviousContactPoint.Y;
            var x2 = currentContactPt.X;
            var y2 = currentContactPt.Y;

            var color = Windows.UI.Colors.Black;
            //var size = 4;

            if (CalculateDistance(x1, y1, x2, y2) > 2.0)
            {
                if (m_Point2.X == 0 && m_Point2.Y == 0)
                {
                    m_Point2 = currentContactPt;
                    return;
                }

                drawBezier(m_Point1, m_Point2, currentContactPt);
                drawBezier(new Point(m_Point1.X + 100, m_Point1.Y), new Point(m_Point2.X + 100, m_Point2.Y), new Point(currentContactPt.X + 100, currentContactPt.Y));

                m_PreviousContactPoint = currentContactPt;
                m_Point1 = currentContactPt;
                m_Point2 = new Point(0, 0);

        }
    }

    }

    private void drawBezier(Point point1, Point point2, Point point3)
    {
        var pathGeometry = new PathGeometry();
        BezierSegment bezier = new BezierSegment()
        {
            Point1 = point1,
            Point2 = point2,
            Point3 = point3
        };

        PathFigure figure = new PathFigure();
        figure.StartPoint = point1;
        figure.Segments.Add(bezier);
       [![enter image description here][1]][1]
        Windows.UI.Xaml.Shapes.Path path = new Windows.UI.Xaml.Shapes.Path();
        path.Stroke = new SolidColorBrush(Colors.Black);
        pathGeometry.Figures.Add(figure);
        path.Data = pathGeometry;
        path.StrokeEndLineCap = PenLineCap.Round;
        path.StrokeStartLineCap = PenLineCap.Round;
        path.StrokeThickness = 4;

        inkCanvas.Children.Add(path);
    }
    private double CalculateDistance(double x1, double y1, double x2, double y2)
    {
        double d = 0;
        d = Math.Sqrt(Math.Pow((x2 - x1), 2) + Math.Pow((y2 - y1), 2));
        return d;
    }

    private void Canvas_PointerReleased(object sender, PointerRoutedEventArgs e)
    {
        IsPressed = false;
    }

此外,这里是C ++ 11的更新(我最喜欢的),它将rec_map声明为别名,可以模板化:

template<class key>
struct rec_map_iterator : map<key, vector<rec_map_iterator<key> > >::iterator
{
    rec_map_iterator(typename map<key, vector<rec_map_iterator<key> > >::iterator i)
        : map<key, vector<rec_map_iterator<key> > >::iterator(i)
    {}
};

这与Potatoswatter的版本相同:

map<int, vector<rec_map_iterator<int>>> m;