Попытка сослаться на ошибку удаленной функции при замене приоритетных очередей

Я просто пытался поменять местами данные между двумя приоритетными очередями и получил эту ошибку. Я также немного погуглил и до сих пор не знаю, что здесь не так.

#include <queue>

class Node
{
public:
    int idx;
};
auto greater = []( const Node& a, const Node&  b) {return a.idx > b.idx; };
using QUEUE  = std::priority_queue<Node, std::vector<Node>, decltype(greater)>;

void foo(QUEUE& a)
{
    QUEUE b(greater);
    a.swap(b);
}

int main()
{

}

Вот полное сообщение об ошибке:

Ошибка C2280 ' ‹ lambda_07efac20ebfa61cc8bb35aebd7d81f7c> &‹‹ lambda_07efac20ebfa61cc8bb35aebd7d81f7c>>::operator =(const ‹‹ lambda_07efac20ebfa61cc8bb35aebd7d81'f7c>> и попытка сослаться на удаленную функцию)


person Stoatman    schedule 14.06.2017    source источник
comment
Кажется, это причуда в Visual Studio. Этот код отлично компилируется на моей машине (clang-802.0.42).   -  person Volodymyr Lashko    schedule 14.06.2017
comment
@Vol Если да, то это тоже особенность GCC 5.1.0.   -  person    schedule 14.06.2017
comment
Здесь играет роль реализация стандартной библиотеки @NeilButterworth. Не компилируется с libstdc++, но компилируется с libc++.   -  person Volodymyr Lashko    schedule 14.06.2017


Ответы (2)


Реализация std::swap в stdlibc++ (и, скорее всего, в стандартной библиотеке для Visual Studio) использует старомодные присваивания:

swap(_Tp& __a, _Tp& __b)
{
    // concept requirements
    __glibcxx_function_requires(_SGIAssignableConcept<_Tp>)

    _Tp __tmp = __a;
    __a = __b;
    __b = __tmp;
}

Напротив, libcxx реализует это с помощью std::move:

swap(_Tp& __x, _Tp& __y) _NOEXCEPT_(is_nothrow_move_constructible<_Tp>::value &&
                                    is_nothrow_move_assignable<_Tp>::value)
{
     _Tp __t(_VSTD::move(__x));
     __x = _VSTD::move(__y);
     __y = _VSTD::move(__t);
}

Чтобы поменять местами объекты типа std::priority_queue, вы должны поменять местами их компараторы, которые представлены в вашем коде как лямбда. Замена лямбды в stdlibc++ невозможна из-за удаленного оператора присваивания копии.

Кстати, нет необходимости использовать лямбду, так как ваш список захвата пуст. Простая функция сделает эту работу.

bool greater(const Node& a, const Node&  b) {return a.idx > b.idx;};
using QUEUE = std::priority_queue<Node, std::vector<Node>, decltype(&greater)>;

void foo(QUEUE&& a)
{
    QUEUE b(&greater);
    a.swap(b);
}

В качестве альтернативы вы можете заменить лямбду вызываемым объектом, который имеет назначение перемещения.

person Volodymyr Lashko    schedule 14.06.2017

В лямбда-выражениях нет операторов присваивания, а swap() использует присваивание. Он будет пытаться использовать назначение для большей лямбды, содержащейся в очереди.

person Community    schedule 14.06.2017