Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to create/pass a completion handler callback as function parameter in c++11?

There is already tonnes of samples/codes out there that shows how to pass a function as callback into function parameter in C++11. Then the callback gets called into a separate function rather than into it's original caller function.

Let's say, i have the following sample code in Objective-C

- (void)calculateSizeWithCompletionBlock:(IPVWebImageCalculateSizeBlock)completionBlock {

    dispatch_async(self.ioQueue, ^{
        NSUInteger fileCount = 0;
        NSUInteger totalSize = 0;

        // Doing some time consuming task, that plays with some local(on this function scope) vars

        if (completionBlock) {
            dispatch_async(dispatch_get_main_queue(), ^{
                completionBlock(fileCount, totalSize);
            });
        }
    });
}

- (void)doSomething {
    NSUInteger var1 = 0;
    NSUInteger var2 = 0;

    [self calculateSizeWithCompletionBlock:^(NSUInteger fileCount, NSUInteger totalSize) {
        // Here, do things with fileCount, totalSize, var1, var2
        NSLog(@"fileCount: %lu, totalSize: %lu, var1: %lu, var2: %lu",(unsigned long)fileCount, (unsigned long)totalSize, (unsigned long)var1, (unsigned long)var2);
    }];
}

The straight question is how can i rewrite the above code in C++11 ? Where my callbacks will be called into the caller function so that it cal use caller functions local vars. I am aware of C++11's Lambda, std::function, std::bind, but not sure how to achieve that.

Any help would be appreciated.

like image 411
Partho Biswas Avatar asked Feb 10 '26 15:02

Partho Biswas


1 Answers

thread_pool& get_threadpool();
void run_on_ui_thread( std::function<void()> );

std::future<void> calculateSizeWithCompletionBlock(
  std::function<void(int fileCount, int totalSize)> completion
) {
  get_threadpool.queue(
    [completion]{
      int fileCount = 0;
      int totalSize = 0;

      // Doing some time consuming task, that plays with some local(on this function scope) vars

      if (completion) {
        RunOnUIThread( [fileCount, totalSize, completion]{
          completion(fileCount, totalSize);
        });
      }
    }
  );
}

void doSomething() {
  int var1 = 0;
  int var2 = 0;

  calculateSizeWithCompletionBlock(
    [var1, var2](int fileCount, int totalSize) {
      // Here, do things with fileCount, totalSize, var1, var2
      std::cout <<
        "fileCount: " << fileCount <<
        ", totalSize: " << totalSize <<
        ", var1: " << var1 <<
        ", var2: " << var2 << "\n";
    }
  );
}

this is the rough equivalent of your code.

I do not include run_on_ui_thread and get_threadpool, because both will depend on what context your C++ program is running in.

This is the only method of thread_pool I use:

struct thread_pool {
  std::future<void> queue( std::function<void()> );
};

basically, it is something that takes a function-like, and returns an object that lets you wait on that task's completion.

Unlike Objective-C, C++ runs on a large myriad of different environments. The services that the OS or whatever other environment it is running in are not fixed.

There isn't, for example, an assumption that all C++ code runs in an interactive UI message-pumping environment. The run_on_ui_thread implicitly assumes that, and would have to be written with the particular ui-thread-pump library in mind.

Some of the above code could be made marginally more efficient in C++14 with move-into-lambda. In particular,

RunOnUIThread( [fileCount, totalSize, completion=std::move(completion)]{
  completion(fileCount, totalSize);
});

as in calculateSizeWithCompletionBlock we don't know how expensive completion is to copy. In C++ you have more access to objects by-value, so sometimes you have to explicitly move things around. On the plus side, this reduces the amount of allocations you'll have to do compared to objective-C.

like image 74
Yakk - Adam Nevraumont Avatar answered Feb 12 '26 16:02

Yakk - Adam Nevraumont



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!