在clang中使用std::async的模板函数
Template function with std::async in clang
我在这里查看std::async
的示例,如下所示:
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <future>
template <typename RAIter>
int parallel_sum(RAIter beg, RAIter end)
{
auto len = std::distance(beg, end);
if(len < 1000)
return std::accumulate(beg, end, 0);
RAIter mid = beg + len/2;
auto handle = std::async(std::launch::async,
parallel_sum<RAIter>, mid, end);
int sum = parallel_sum(beg, mid);
return sum + handle.get();
}
int main()
{
std::vector<int> v(10000, 1);
std::cout << "The sum is " << parallel_sum(v.begin(), v.end()) << 'n';
}
我尝试用Clang 3.4的web编译器编译它,结果输出The sum is
而不是预期的The sum is 1000
。
我复制了这个例子并在Ubuntu 14.04.1 64位上使用clang 3.5-1ubuntu1/gcc 4.8编译,使用以下命令:
clang++ -g main.cpp -std=c++1y -o out -pthread;
我得到以下错误:
main.cpp:15:19: error: no matching function for call to 'async'
auto handle = std::async(std::launch::async,
^~~~~~~~~~
main.cpp:24:35: note: in instantiation of function template specialization
'parallel_sum<__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> >
> >' requested here
std::cout << "The sum is " << parallel_sum(v.begin(), v.end()) << 'n';
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/future:1523:5: note:
candidate template ignored: substitution failure [with _Fn = int
(__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >,
__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >), _Args =
<__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > &,
__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > &>]:
function cannot return function type 'int (__gnu_cxx::__normal_iterator<int *,
std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int *,
std::vector<int, std::allocator<int> > >)'
async(launch __policy, _Fn&& __fn, _Args&&... __args)
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/future:1543:5: note:
candidate template ignored: substitution failure [with _Fn = std::launch, _Args = <int
(__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >,
__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >),
__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > &,
__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > &>]: no
type named 'type' in 'std::result_of<std::launch (int
(*)(__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >,
__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >),
__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > &,
__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > &)>'
async(_Fn&& __fn, _Args&&... __args)
^
1 error generated.
make: *** [all] Error 1
这是clang, gcc, libstdc++中的错误,还是我错过了什么?
我认为这是clang++的一个bug。除非有我不知道的奇怪限制规则,引用函数的id表达式是左值。然而,clang++在推导通用引用时区分了函数模板特化和普通函数:
#include <iostream>
template<class T>
void print_type()
{
std::cout << __PRETTY_FUNCTION__ << "n";
}
template <class T>
int foo(bool) { return 42; }
int bar(bool) { return 42; }
template<class T>
void deduce(T&&)
{
print_type<T>();
}
int main()
{
deduce(foo<bool>);
deduce(bar);
}
clang++的输出,包括早期的3.5版本:
<>之前void print_type() [T = int (bool)]void print_type() [T = int (&)(bool)]之前生活例子
std::result_of
在libstdc++的std::async
实现中用于获取函数的返回类型(从这里的片段):
template<typename _Fn, typename... _Args>
future<typename result_of<_Fn(_Args...)>::type>
async(launch __policy, _Fn&& __fn, _Args&&... __args)
如果传递foo<bool>
作为第二个参数,clang++会推导出_Fn == int (bool)
。
函数(对象)的类型与result_of
的参数类型相结合。这可能是c++ 03遗留下来的,在那里我们还没有可变模板。传递参数类型是为了允许result_of
解析重载函数,就像在_Fn
是类类型的情况下解析重载的operator()
一样。
但是,如果_Fn
不是推导为函数引用,而是推导为函数类型,则_Fn(_Args...)
的组合形成了一个非法类型:函数返回函数:
但还有更多:上述async
的申报有缺陷,见LWG 2021。Howard Hinnant将libc++中的声明更改为:
template <class F, class... Args>
future < typename result_of<
typename decay<F>::type(typename decay<Args>::type...)
>::type
>
async(launch policy, F&& f, Args&&... args);
so libc++将函数衰减为函数指针。缺少左值引用导致的问题消失。
相关文章:
- 为什么std::async使用同一个线程运行函数
- 为什么我不能将引用作为 std::async 的函数参数传递
- async中没有匹配的函数(模板中未解析的类型)
- 在Visual Studio中,与std::async一起使用时不调用"thread_local"变量"析构函数,这是一个错误吗?
- C++从 std::async 函数读取命名空间中的全局变量标志
- 如何将函数及其参数传递给成员函数内的 std::async
- 使用 std::async 调用模板函数的正确方法是什么?
- 为什么不能将std :: async用于接收对抽象类作为参数的函数
- 没有与参数列表匹配的重载函数"async"实例
- 通过 std::async 启动的函数引发的异常会发生什么情况
- 如何在成员函数上使用 std::async
- std::async 和 lambda 函数在C++中没有给出关联的状态
- 如何使用“std::async”在互斥锁保护循环中调用函数
- 如何将函数参数传递给boost::async()
- std::async, std::函数对象和带有'callable'参数的模板
- std::async 可以与模板函数一起使用吗?
- 如何为返回async结果的函数指定函数签名
- 将std::async与模板函数结合使用
- 用std::async调用带unique_ptr类型的函数
- Boost async函数编译错误