Ошибка C2064 Visual Studio 2022

Имеется класс SnakeBody, он содержит в функции update использование предиката &SnakeBody::removeTurnsPredicate, которое, содя по всему, не хочет компилироваться. Возникает ошибка: C2064 Результатом вычисления фрагмента не является функция, принимающая 1 аргументов. Вызов turns.erase(remove_if(turns.begin(), turns.end(), &SnakeBody::removeTurnsPredicate), turns.end()); призван удалить нужные элементы в векторе. В чем может быть проблема?:

class SnakeBody: public SnakePart
{
public:
    vector<turn> turns;
public:
    SnakeBody(String F, float X, float Y, float W, float H) :SnakePart(X, Y, W, H) {
        sprite.setTextureRect(IntRect(1 * W, 0 * H, W, H));
        sprite.setOrigin(W / 2, H / 2);
    };
    void update(float time);
    bool removeTurnsPredicate(turn turn);
};

Второй:

#include <iostream> 
#include <SFML/Graphics.hpp>
#include <list>
using namespace sf;
using namespace std;
class SnakePart
{
public:
    float x, y, w, h, dx, dy, speed = 0; //координаты игрока х и у, высота ширина, ускорение (по х и по у), сама скорость
    int dir = 0; //направление (direction) движения игрока
    float currentFrame = 0;
    static String File; //файл с расширением
    static Image image;//сфмл изображение
    static Texture texture;//сфмл текстура
    Sprite sprite;

    SnakePart(float X, float Y, float W, float H) {  //Конструктор с параметрами(формальными) для класса Player. При создании объекта класса мы будем задавать имя файла, координату Х и У, ширину и высоту
        w = W; h = H;//высота и ширина
        sprite.setTexture(texture);
        x = X; y = Y;//координата появления спрайта
    }

    static void init();
public:
    virtual void update(float time) = 0;
};

struct turn
{
    float x, y, speed;
    int fromDir, dir;
    bool applied;
    bool beRemoved;
};

И сам cpp для SnakeBody:

#include "SnakeBody.h"

bool SnakeBody::removeTurnsPredicate(turn turn) {
    return turn.beRemoved == true;
}

void SnakeBody::update(float time) {
    turns.erase(remove_if(turns.begin(), turns.end(), &SnakeBody::removeTurnsPredicate), turns.end());
    switch (dir)
    {
    case 0: dx = speed; dy = 0;   break;
    case 1: dx = -speed; dy = 0;   break;
    case 2: dx = 0; dy = speed;   break;
    case 3: dx = 0; dy = -speed;   break;
    }

    x += dx;
    y += dy;

    sprite.setPosition(x, y);

    for (auto it = turns.begin(); it != turns.end(); it++) {
        if ((it->x == x) && (it->y == y) && (it->applied == false)) {
            if ((it->fromDir == 1) && (it->dir == 3)) {
                sprite.setTextureRect(IntRect(0 * w, 1 * h, w, h));
            }
            if ((it->fromDir == 0) && (it->dir == 3)) {
                sprite.setTextureRect(IntRect(2 * w, 2 * h, w, h));
            }
            if ((it->fromDir == 1) && (it->dir == 2)) {
                sprite.setTextureRect(IntRect(0 * w, 0 * h, w, h));
            }
            if ((it->fromDir == 0) && (it->dir == 2)) {
                sprite.setTextureRect(IntRect(2 * w, 0 * h, w, h));
            }
            dir = it->dir;
            speed = it->speed;
            it->applied = true;
        }
        if (it->applied == true) {
            if ((dir == 0) || (dir == 1)) {
                sprite.setTextureRect(IntRect(1 * w, 0 * h, w, h));
            }
            else
            {
                sprite.setTextureRect(IntRect(2 * w, 1 * h, w, h));
            }
            it->beRemoved = true;
        }
    }
    
}

Ответы (1 шт):

Автор решения: HolyBlackCat

removeTurnsPredicate - это нестатическая функция-член.

Ее нельзя просто вызвать как обычную функцию: removeTurnsPredicate(x);. Нужно передать объект, на котором вызывать: объект.removeTurnsPredicate(x);. (Внутри class SnakeBody сработает и без объект., но там автоматически добавляется this->.)

std::remove_if не предназначен для таких вызовов. Он не будет добавлять объект. к вызову, и тем более ему негде взять подходящий объект. (Специально упрощаю. &SnakeBody::removeTurnsPredicate - это указатель-на-член, и синтаксис вызова для него - (объект.* &SnakeBody::removeTurnsPredicate)(x);).

Есть несколько вариантов решения:

  • Сделать removeTurnsPredicate static (или выдвинуть наружу класса), чтобы для его вызова не нужен был экземпляр SnakeBody (и заодно поменять параметр const turn &t - чтобы лишний раз не копировать объекты).

    Заодно убрать SnakeBody::, оставить только &removeTurnsPredicate.

  • Вообще убрать removeTurnsPredicate, вместо него передавать лямбду: remove_if(..., [](const turn &t){return t.beRemoved;}).

  • Использовать std::mem_fn вместо лямбды: std::mem_fn(&turn::beRemoved). Эффект тот же, но понтов больше.

Ну и turns.erase(remove_if(turns.begin(), turns.end(), /*??*/), turns.end()); можно и нужно сократить до std::erase_if(turns, /*??*/);.

→ Ссылка