2017-05-09 55 views
2

已经有大量的样本/代码显示如何将函数作为回调函数传递到C++ 11中的函数参数中。然后回调被调用到一个单独的函数中,而不是调用它的原始调用者函数。如何在C++ 11中创建/传递完成处理程序回调函数参数?

比方说,我已经在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); 
    }]; 
} 

下面的示例代码直的问题是如何能够改写C++ 11上面的代码? 我的回调将被调用到调用者函数中,以便它使用调用者函数local vars。我知道C++ 11的Lambda,std :: function,std :: bind,但不知道如何实现。

任何帮助,将不胜感激。

+0

我写的这篇文章可能会让你感兴趣:https://vittorioromeo.info/index/blog/passing_functions_to_functions.html –

+0

你是否试图在调用GCD或更一般地用C++ lambda替换obj-c闭包? GCD有一个c样式的回调接口以及一个基于闭包的接口。您可以将闭包对象的地址和函数指针传递给它的静态函数。这可以包装在回调函数对象中。 –

+0

我不知道Objective-C,但在我看来,你想用'[&]'lambda捕获来实现。 – yzt

回答

2
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"; 
    } 
); 
} 

这与您的代码大致相当。

我不包括run_on_ui_threadget_threadpool,因为两者都将取决于你的C++程序在运行的情况下

这是thread_pool的唯一方法我用:

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

基本上,它是类似于函数的东西,并返回一个对象,让您等待该任务完成。与Objective-C不同,C++在大量不同的环境中运行。操作系统或其他运行环境的服务不固定。例如,不存在所有C++代码都在交互式UI消息抽取环境中运行的假设。 run_on_ui_thread隐含地假定,并且必须记住特定的ui-thread-pump库。

上述代码中的一部分可以通过移入lambda在C++ 14中稍微更高效。特别是,

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

calculateSizeWithCompletionBlock我们不知道completion是多么昂贵复制。在C++中,您可以更多地访问对象,所以有时您必须明确移动。从好的一面来看,这减少了与Objective-C相比必须做的分配量。

相关问题