Заменить значения вызова для std::function

Я сохранил std::function, которые являются результатами std::bindв списке:

typedef std::pair<int, std::function<void(HDC)>> myPair;

std::list<myPair> *paintJobs;
paintJobs = new std::list<myPair>();

Я тогда добавляю что-то вроде этого:

int id = 1;
int x = 0;
int y = 0;
int width = 100;
int height = 100;
int r = 255;
int g = 0;
int b = 0;
std::function<void(HDC)> func = std::bind(&Window::drawRect, this, std::placeholders::_1, x, y, width, height, r, g, b);
paintJobs->push_back(std::make_pair(id, func));

В моем методе рисования я просматриваю список и вызываю все добавленные функции. Эта часть работает хорошо.

Но теперь я хочу заменить, например, цвет (r, g и b):

void changeColor(int id, int r, int g, int b) {
   for(auto elem = paintJobs->begin(); elem != paintJobs->end(); ++elem) {
        if(elem->first == id){

            //change the 6th, 7th and 8th parameter of elem->second
        }
    }
}

Моя другая идея состояла в том, чтобы вставить новую запись и скопировать старые значения, но есть другая проблема: получение связанных значений.

Так как же я могу заменить связанные значения параметров или получить значения других?

2 ответа

Решение

Магазин std::function<void(HDC, int r, int g, int b)> (или эквивалент) вместо std::function<void(HDC)>, Также хранить struct {int r,g,b;},

struct rgb { int r,g,b; };
struct rgb_func {
  rgb color;
  std::function<void(HDC, rgb)> f;
  void operator()(HDC hdc)const{
    return f(hdc, color);
  }
};

std::function<void(HDC, rgb)> func =
  [this, x, y, width, height](HDC hdc, rgb color)->void
  {
    this->drawRect( hdc, x, y, width, height, color.r, color.g, color.b );
  };
paintJobs->push_back(std::make_pair(id, rgb_func{ {r,g,b}, func }));

затем изменить его:

void changeColor(int id, int r, int g, int b) {
  for(auto elem = paintJobs->begin(); elem != paintJobs->end(); ++elem) {
    if(elem->first == id){
      elem->second.color = {r,g,b};
    }
  }
}

обратите внимание, что тип second больше не std::function<void(HDC)>, но она конвертируема в std::function<void(HDC)> но не от этого. Такое преобразование может привести к скромным накладным расходам; использование auto& бы избежать этого в этом случае.

Код не проверен; дизайн это звук. Там, наверное, тпёсь. я бы сделал rgb быть немного лучше (например, гарантировать обнуление или что-то еще).

Я использовал лямбду вместо std::bind, так как std::bind сбивает с толку и был в значительной степени устарел, когда он был добавлен в std,

Как в сторону

void changeColor(int id, int r, int g, int b) {
  for(auto& elem:*paintJobs) {
    if(elem.first == id){
      elem.second.color = {r,g,b};
    }
  }
}

намного менее грязный

Вы можете сделать решение, подобное следующему:

  1. Храните ваши связанные параметры в другом месте.
  2. Перейдите к вашей функции std::bind(f, ..., std::ref(param)...)

Идея состоит в том, чтобы иметь возможность изменять параметры:

std::function<void(HDC)> func = std::bind(&Window::drawRect, this, std::placeholders::_1, std::ref(x)...

Теперь вы можете изменять параметры извне, при повторном вызове функции будут использоваться новые значения.

Другим решением будет изменить подпись вашего std::function взять параметры для каждого звонка.

Другие вопросы по тегам