替换std :: function的调用值

时间:2017-02-09 18:37:36

标签: c++ c++11 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 个答案:

答案 0 :(得分:1)

存储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的使用会避免它。

未经测试的代码;设计很健全。可能有tpyos。我会让std::bind变得更好(比如,保证归零等)。

我使用的是lambda而不是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}; } } } 时已经过时了。

作为旁白

<html> 
<head> 
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js" type="text/javascript"></script> 
<script src="http://www.skulpt.org/static/skulpt.min.js" type="text/javascript"></script> 
<script src="http://www.skulpt.org/static/skulpt-stdlib.js" type="text/javascript"></script> 

</head> 

<body> 

<script type="text/javascript"> 
// output functions are configurable.  This one just appends some text
// to a pre element.
function outf(text) { 
    var mypre = document.getElementById("output"); 
    mypre.innerHTML = mypre.innerHTML + text; 
} 
function builtinRead(x) {
    if (Sk.builtinFiles === undefined || Sk.builtinFiles["files"][x] === undefined)
            throw "File not found: '" + x + "'";
    return Sk.builtinFiles["files"][x];
}
// Here's everything you need to run a python program in skulpt
// grab the code from your textarea
// get a reference to your pre element for output
// configure the output function
// call Sk.importMainWithBody()
function runit() { 
   var prog = document.getElementById("yourcode").value; 
   var mypre = document.getElementById("output"); 
   mypre.innerHTML = ''; 
   Sk.pre = "output";
   Sk.configure({output:outf, read:builtinRead}); 
   (Sk.TurtleGraphics || (Sk.TurtleGraphics = {})).target = 'mycanvas';
   var myPromise = Sk.misceval.asyncToPromise(function() {
       return Sk.importMainWithBody("<stdin>", false, prog, true);
   });
   myPromise.then(function(mod) {
       console.log('success');
   },
       function(err) {
       console.log(err.toString());
   });
} 
</script> 

<h3>Try This</h3> 
<form> 
<textarea id="yourcode" cols="40" rows="10">import turtle

t = turtle.Turtle()
t.forward(100)

print "Hello World" 
</textarea><br /> 
<button type="button" onclick="runit()">Run</button> 
</form> 
<pre id="output" ></pre> 
<!-- If you want turtle graphics include a canvas -->
<div id="mycanvas"></div> 

</body> 

</html> 

不那么凌乱。

答案 1 :(得分:0)

您可以执行以下解决方案:

  1. 将绑定参数存储在其他位置。
  2. 传递给您的函数std::bind(f, ..., std::ref(param)...)
  3. 我们的想法是能够修改参数:

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

    现在您可以从外部修改参数,当再次调用该函数时,它将使用新值。

    另一种解决方案是更改std::function的签名,以便为每次通话获取参数。