我在使用C++ 11进行实验时偶然发现了这一点.我发现它是一个明显的解决方案,但我还没有在野外找到任何其他的例子,所以我担心我会遗漏一些东西.
我所指的做法(在"addAsync"函数中):
#include <thread>
#include <future>
#include <iostream>
#include <chrono>
int addTwoNumbers(int a, int b) {
std::cout << "Thread ID: " << std::this_thread::get_id() << std::endl;
return a + b;
}
void printNum(std::future<int> future) {
std::cout << future.get() << std::endl;
}
void addAsync(int a, int b, auto callback(std::future<int>) -> void) { //<- the notation in question
auto res = std::async(std::launch::async, addTwoNumbers, a, b);
if (callback) //super straightforward nullptr handling
return callback(std::move(res));
}
int main(int argc, char** argv) {
addAsync(10, 10, [](std::future<int> number) { //lambda functions work great
addAsync(number.get(), 20, [](std::future<int> number) {
addAsync(893, 4387, printNum); //as do standard functions
addAsync(2342, 342, nullptr); //executes, sans callback
std::cout << number.get() << std::endl;
});
});
std::cout << "main thread: " << std::this_thread::get_id() << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它被认为是不好的做法,还是不可移植(我只在MSVC++ 2015中尝试过)?另外,编译器如何处理这个问题; 通过转换为std :: function?
我很乐意在我的项目中继续使用它,因为它显然在"签名"中声明了所需的参数类型和返回类型,接受了nullptr的可选性,并且似乎"正常工作"(我知道这些是最后着名的C++中的单词).
Yak*_*ont 17
auto callback(std::future<int>) -> void
是被void(std::future<int>)
称为类型的实体的声明callback
.当作为参数列出时,编译器将其调整为类型的指针函数void(*)(std::future<int>)
.
你的lambda是无状态的,因此可以隐式转换为函数指针.
一旦你添加了一个非平凡的捕获,你的代码将停止编译:
[argc](std::future<int> number) {
std::cout << argc << '\n';
Run Code Online (Sandbox Code Playgroud)
...
现在,忽略你的问题内容并查看标题......
a的成本适中,std::function
因为它是值类型,而不是视图类型.作为一个值类型,它实际上复制了它的参数.
您可以通过将调用对象包装在a中来解决此问题std::ref
,但是如果您想要声明"我不会将此函数对象保留的时间长于此调用",则可以function_view
按如下方式编写类型:
template<class Sig>
struct function_view;
template<class R, class...Args>
struct function_view<R(Args...)> {
void* ptr = nullptr;
R(*pf)(void*, Args...) = nullptr;
template<class F>
using pF = decltype(std::addressof( std::declval<F&>() ));
template<class F>
void bind_to( F& f ) {
ptr = (void*)std::addressof(f);
pf = [](void* ptr, Args... args)->R{
return (*(pF<F>)ptr)(std::forward<Args>(args)...);
};
}
// when binding to a function pointer
// even a not identical one, check for
// null. In addition, we can remove a
// layer of indirection and store the function
// pointer directly in the `void*`.
template<class R_in, class...Args_in>
void bind_to( R_in(*f)(Args_in...) ) {
using F = decltype(f);
if (!f) return bind_to(nullptr);
ptr = (void*)f;
pf = [](void* ptr, Args... args)->R{
return (F(ptr))(std::forward<Args>(args)...);
};
}
// binding to nothing:
void bind_to( std::nullptr_t ) {
ptr = nullptr;
pf = nullptr;
}
explicit operator bool()const{return pf;}
function_view()=default;
function_view(function_view const&)=default;
function_view& operator=(function_view const&)=default;
template<class F,
std::enable_if_t< !std::is_same<function_view, std::decay_t<F>>{}, int > =0,
std::enable_if_t< std::is_convertible< std::result_of_t< F&(Args...) >, R >{}, int> = 0
>
function_view( F&& f ) {
bind_to(f); // not forward
}
function_view( std::nullptr_t ) {}
R operator()(Args...args) const {
return pf(ptr, std::forward<Args>(args)...);
}
};
Run Code Online (Sandbox Code Playgroud)
实例.
这也是有用的,因为它是一种严格简单的类型擦除std::function
,因此它可能具有教育意义.
归档时间: |
|
查看次数: |
2405 次 |
最近记录: |