C++ - 如何使用reference_wrapper向量

C++ - How to use a vector of reference_wrapper

本文关键字:wrapper 向量 reference 何使用 C++      更新时间:2023-10-16

我正在尝试重构我拥有的路径查找算法的一部分,该算法使用指针不使用指针。不幸的是,我对参考文献并不了解。我收到错误:Invalid operands to binary expression ('std::__1::reference_wrapper<Tile>' and 'const std::__1::reference_wrapper<Tile>')

我也不知道这意味着什么。我的代码在下面,我可以收集它来自以下行:openList.erase(std::find(openList.begin(), openList.end(), current));但我不确定如何解决这个问题。

bool TileMap::tilesBetween(Tile& p_start, Tile& p_end)
{
    std::vector<std::reference_wrapper<Tile>> openList;
    std::vector<std::reference_wrapper<Tile>> closedList;
    openList.push_back(p_start);
    do
    {
        std::sort(openList.begin(), openList.end(), sortF());
        Tile& current = openList[0];
        closedList.push_back(current);
        openList.erase(std::find(openList.begin(), openList.end(), current));
        if(std::find(closedList.begin(), closedList.end(), p_end) != closedList.end())
        {
            return true;
        }
        std::vector<std::reference_wrapper<Tile>> adjacentTiles;
        if (current.m_coordinates.x > 0)
        {
            adjacentTiles.push_back(m_tiles[current.m_coordinates.y * m_width + (current.m_coordinates.x - 1)]);
        }
        if (current.m_coordinates.x < m_width)
        {
            adjacentTiles.push_back(m_tiles[current.m_coordinates.y * m_width + (current.m_coordinates.x + 1)]);
        }
        if (current.m_coordinates.y > 0)
        {
            adjacentTiles.push_back(m_tiles[(current.m_coordinates.y - 1) * m_width + current.m_coordinates.x]);
        }
        if (current.m_coordinates.y < m_height)
        {
            adjacentTiles.push_back(m_tiles[(current.m_coordinates.y + 1) * m_width + current.m_coordinates.x]);
        }
        for(auto t : adjacentTiles)
        {
            if(std::find(closedList.begin(), closedList.end(), t) != closedList.end())
            {
                continue;
            }
            if(std::find(openList.begin(), openList.end(), t) == closedList.end())
            {
                openList.push_back(t);
            }
        }
    }
    while(!openList.empty());
    return false;
}

编辑:发布sortF

struct sortF
{
    bool operator()(const Tile* p_a, const Tile* p_b) const
    {
        return p_a->f < p_b->f;
    }
};

更新:根据建议,我已将函数更改为使用指针而不是引用。它似乎正在工作,但在完成之前我还有更多要实现。

bool TileMap::tilesBetween(Tile* p_start, Tile* p_end)
{
    std::vector<Tile*> openList;
    std::vector<Tile*> closedList;
    std::cout << p_start << ", ";
    openList.push_back(p_start);
    do
    {
        std::sort(openList.begin(), openList.end(), sortF());
        Tile* current = openList[0];
        closedList.push_back(current);
        openList.erase(std::find(openList.begin(), openList.end(), current));
        if(std::find(closedList.begin(), closedList.end(), p_end) != closedList.end())
        {
            return true;
        }
        std::vector<Tile*> adjacentTiles;
        if (current->m_coordinates.x > 0)
        {
            adjacentTiles.push_back(&m_tiles[current->m_coordinates.y * m_width + (current->m_coordinates.x - 1)]);
        }
        if (current->m_coordinates.x < m_width)
        {
            std::cout << &m_tiles[current->m_coordinates.y * m_width + (current->m_coordinates.x + 1)] << std::endl;
            adjacentTiles.push_back(&m_tiles[current->m_coordinates.y * m_width + (current->m_coordinates.x + 1)]);
        }
        if (current->m_coordinates.y > 0)
        {
            adjacentTiles.push_back(&m_tiles[(current->m_coordinates.y - 1) * m_width + current->m_coordinates.x]);
        }
        if (current->m_coordinates.y < m_height)
        {
            adjacentTiles.push_back(&m_tiles[(current->m_coordinates.y + 1) * m_width + current->m_coordinates.x]);
        }
        for(auto t : adjacentTiles)
        {
            if(std::find(closedList.begin(), closedList.end(), t) != closedList.end())
            {
                continue;
            }
            if(std::find(openList.begin(), openList.end(), t) == openList.end())
            {
                openList.push_back(t);
            }
        }
    }
    while(!openList.empty());
    return false;
}

我可以收集到它来自以下行:openList.erase(std::find(openList.begin(), openList.end(), current)); 但我不确定如何解决这个问题。

std::find遍历std::reference_wrapper<Tile>,而不是Tile&本身。因此

    Tile& current = openList[0];
    openList.erase(std::find(openList.begin(), openList.end(), current));

是不正确的。将其更改为

    openList.erase(std::find_if(openList.begin(), openList.end(), [&](const std::reference_wrapper<Tile> &i)
    {
        return i.get() == current;
    }));

std::reference_wrapper::get返回基础引用。

一个简单的工作示例来证明这一点

#include <algorithm>
#include <list>
#include <vector>
#include <iostream>
#include <functional>
struct S
{
    int val;
    S(int i) : val(i) {}
};
int main()
{
    std::list<S> l = {-4, -3, -2, -1, 0, 1, 2, 3, 4};
    std::vector<std::reference_wrapper<S>> v(l.begin(), l.end());
    auto& x = l.front();
    v.erase(std::find_if(v.cbegin(), v.cend(), [&](const std::reference_wrapper<S> &i)
    {
        return i.get().val == x.val;
    }));
    std::cout << v[0].get().val;
}

你的问题在这里:

std::sort(openList.begin(), openList.end(), sortF());

您的sortF是无效的比较对象。operator()必须如下所示:

bool operator()(const Tile& lhs, const Tile& rhs) const
//              ^^^ ref ^^^      ^^^ ref ^^^
{
    return lhs.f < rhs.f;
}

而不是:

bool operator()(const Tile* p_a, const Tile* p_b) const
//              ^^^ ptr ^^^      ^^^ ptr ^^^

你有一个reference_wrapper<Tile>向量,而不是Tile*向量。