Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does std::tr1::function work with Objective-C Blocks?

I was pretty surprised when I found that the following code actually works:

std::vector<int> list /*= ...*/;
std::tr1::function<void(int)> func = ^(int i) {
  return i + 1;
};

std::for_each(list.begin(), list.end(), func);

Seems like std::tr1::function is capable of being constructed from an Objective-C block, but I'm not sure quite how, since (last I checked), its implementation doesn't specifically handle blocks. Is it somehow implicitly sucking out the underlying function pointer? Also, is this behavior undefined and likely to change?

like image 950
Jonathan Sterling Avatar asked Apr 09 '11 19:04

Jonathan Sterling


1 Answers

Update: I was wrong, here's why it really works

std::tr1::function's template parameter simply defines the signature of the resulting function object, not the type it actually wraps. Thus, the wrapped object only needs to offer an operator() with matching signature. Block references, like function pointers, have such an operator() implicitly (obviously, so you can call them).

Old, incorrect answer (so the comments make sense)

I strongly suspect it works because the block doesn't capture any variables from the surrounding scope. In that case, there is no state to maintain, so a block reference can be represented as a bare function pointer. If we change the code to

std::vector<int> list /*= ...*/;
int counter = 0;
std::tr1::function<void(int)> func = ^(int i) {
  counter++;
  return i + counter;
};

std::for_each(list.begin(), list.end(), func);

it should fail to compile, as the block must carry the captured value of counter around with it. (unless of course the implementation of std::tr1::function has been specifically updated to support blocks)

like image 172
pmdj Avatar answered Oct 21 '22 11:10

pmdj