Template function with std :: async in clang

I looked at the std::async example here :

 #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'; } 

I tried to compile it with a web compiler for Clang 3.4, and it led to the conclusion The sum is instead of the expected The sum is 1000 .

I copied this example and compiled with clang 3.5-1ubuntu1 / gcc 4.8 on Ubuntu 14.04.1 64-bit using the following command:

 clang++ -g main.cpp -std=c++1y -o out -pthread; 

I get the following error:

 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 

Is this a bug in clang, gcc, libstdc ++ or am i missing something?

+6
source share
1 answer

I think this is a bug in clang ++. If there is no weird bounded rule that I don't know about, the id expression related to the function is the value of lvalue. However, clang ++ makes a distinction between specialization of function templates and ordinary functions in the output for a universal reference:

 #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); } 

Conclusion, clang ++ up to early 3.5:

  void print_type () [T = int (bool)]
 void print_type () [T = int (&) (bool)]

Living example


std::result_of used in the implementation of libstd ++ std::async to get the return type of the function ( fragment from here ):

 template<typename _Fn, typename... _Args> future<typename result_of<_Fn(_Args...)>::type> async(launch __policy, _Fn&& __fn, _Args&&... __args) 

If we pass foo<bool> as the second argument, clang ++ prints _Fn == int (bool) .

The type of the function (object) is combined with the argument types for result_of . This is probably a relic of C ++ 03, where we did not yet have variation patterns. Argument types are passed to allow result_of to allow overloaded functions, such as operator() overloaded, in case _Fn is a class type.

However, if _Fn is displayed not on the function reference, but on the type of the function, the combination _Fn(_Args...) forms an illegal type: function returning the function:

  _Fn == int (bool)
      _Args ... == bool
 ==> _Fn (_Args ...) == int (bool) (bool)

But there is more to it: the async declaration above is defective, see LWG 2021 . Howard Hinnant changed the declaration in libC ++ to:

 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); 

therefore libC ++ decomposes the function into a function pointer. The problem caused by the lack of a reference to the lvalue value disappears.

+3
source

Source: https://habr.com/ru/post/973493/


All Articles