0

The following code compiles on Windows under MSVC 2022 in a C++17 mode, but fails to compile on Linux with both GCC 11.3 and Clang 16.0 compilers.

#include <vector>
#include <future>
#include <numeric>
#include <thread>

using namespace std;

template <class T>
T parallel_accumulate(const std::vector<T>& v)
{
  packaged_task pt0{accumulate<const T*, T>};
  packaged_task pt1{accumulate<const T*, T>};

  future f0{pt0.get_future()};
  future f1{pt1.get_future()};

  thread t0{move(pt0), &v[0], &v[v.size() / 2], 0};
  thread t1{move(pt1), &v[v.size() / 2], &v[0] + v.size(), 0};

  t0.join();
  t1.join();

  return f0.get() + f1.get();
}

#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest/doctest.h>

TEST_CASE("accumulate")
{
  constexpr size_t checks_count = 10;

  std::vector<int> v;
  v.reserve(checks_count);

  for (size_t i = 1; i <= checks_count; ++i)
  {
    v.push_back(i);
    CHECK(parallel_accumulate(v) == i * (i + 1) / 2);
  }
}

The error under GCC is:

/home/bobeff/projects/cpp/cpp_programming_language/05_a_tour_of_cpp_concurrency_and_utilities/packaged_task.cpp:39:5:   required from here
/home/bobeff/projects/cpp/cpp_programming_language/05_a_tour_of_cpp_concurrency_and_utilities/packaged_task.cpp:11:17: error: class template argument deduction failed:
   11 |   packaged_task pt0{accumulate<const T*, T>};
      |                 ^~~
/home/bobeff/projects/cpp/cpp_programming_language/05_a_tour_of_cpp_concurrency_and_utilities/packaged_task.cpp:11:17: error: no matching function for call to ‘packaged_task(<unresolved overloaded function type>)’
In file included from /home/bobeff/projects/cpp/cpp_programming_language/05_a_tour_of_cpp_concurrency_and_utilities/packaged_task.cpp:2:
/usr/include/c++/11/future:130:11: note: candidate: ‘template<class _Signature> packaged_task()-> std::packaged_task<_Signature>’
  130 |     class packaged_task;
      |           ^~~~~~~~~~~~~
/usr/include/c++/11/future:130:11: note:   template argument deduction/substitution failed:
/home/bobeff/projects/cpp/cpp_programming_language/05_a_tour_of_cpp_concurrency_and_utilities/packaged_task.cpp:11:17: note:   candidate expects 0 arguments, 1 provided
   11 |   packaged_task pt0{accumulate<const T*, T>};
      |                 ^~~
In file included from /home/bobeff/projects/cpp/cpp_programming_language/05_a_tour_of_cpp_concurrency_and_utilities/packaged_task.cpp:2:
/usr/include/c++/11/future:130:11: note: candidate: ‘template<class _Signature> packaged_task(std::packaged_task<_Signature>)-> std::packaged_task<_Signature>’
  130 |     class packaged_task;
      |           ^~~~~~~~~~~~~
/usr/include/c++/11/future:130:11: note:   template argument deduction/substitution failed:
/home/bobeff/projects/cpp/cpp_programming_language/05_a_tour_of_cpp_concurrency_and_utilities/packaged_task.cpp:11:17: note:   mismatched types ‘std::packaged_task<_Signature>’ and ‘int (*)(const int*, const int*, int)’
   11 |   packaged_task pt0{accumulate<const T*, T>};
      |                 ^~~
/home/bobeff/projects/cpp/cpp_programming_language/05_a_tour_of_cpp_concurrency_and_utilities/packaged_task.cpp:11:17: note:   couldn’t deduce template parameter ‘_Signature’

and under Clang it is:

/home/bobeff/projects/cpp/cpp_programming_language/05_a_tour_of_cpp_concurrency_and_utilities/packaged_task.cpp:11:17: error: no viable constructor or deduction guide for deduction of template arguments of 'packaged_task'
  packaged_task pt0{accumulate<const T*, T>};
                ^
/home/bobeff/projects/cpp/cpp_programming_language/05_a_tour_of_cpp_concurrency_and_utilities/packaged_task.cpp:39:11: note: in instantiation of function template specialization 'parallel_accumulate<int>' requested here
    CHECK(parallel_accumulate(v) == i * (i + 1) / 2);
          ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/future:130:11: note: candidate template ignored: could not match 'packaged_task<_Signature>' against 'int (*)(const int *, const int *, int)'
    class packaged_task;
          ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/future:130:11: note: candidate function template not viable: requires 0 arguments, but 1 was provided

Why does class template arguments deduction fail under GCC/Clang and how to fix the code to work on all compilers?

bobeff
  • 3,543
  • 3
  • 34
  • 62

2 Answers2

2

The deduction guides for packaged_task were added after LWG3117, so you need a compiler such as gcc-12 that already implements it.

康桓瑋
  • 33,481
  • 5
  • 40
  • 90
0

As it was mentioned by the 康桓瑋's response the problem is the missing deduction guides from the standard library. My solution is to provide them in my own code in the std namespace.

namespace std {

template <class T>
packaged_task(T (*)(const T*, const T*, T)) -> packaged_task<T (const T*, const T*, T)>;

}

Attention:

As it was mentioned by iboB in a private chat this will probably not work with the libc++ because it does not use the std namespace.

bobeff
  • 3,543
  • 3
  • 34
  • 62