Search code examples
c++c++11std-function

Replace invocation values for std::function


I have stored std::function, which are results of std::bind, in a list:

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

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

I then I add something like this:

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));

In my paint method I go through the list and call all the functions, I have added. This part works well.

But now, I want to exchange for example the color (the r, g and 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
        }
    }
}

My other idea was to insert a new entry and copying the old values, but there is the other problem: getting the bound values.

So how can I replace the bound values of the parameters or getting the values of the other ones?


Solution

  • Store a std::function<void(HDC, int r, int g, int b)> (or equivalent) instead of a std::function<void(HDC)>. Also store a 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 }));
    

    then to change it:

    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};
        }
      }
    }
    

    note that the type of second is no longer a std::function<void(HDC)>, but it is convertible-to a std::function<void(HDC)> but not from it. Such conversion could result in modest overhead; use of auto& would avoid it in that case.

    Code not tested; design is sound. There are probably tpyos. I would make rgb be a bit nicer (like, guarantee zeroing or whatever).

    I used lambda instead of std::bind, because std::bind is confusing and was pretty much obsolete when it was added to std.

    As an aside

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

    is a lot less messy.