Search code examples
c++templatesc++17template-argument-deductionclass-template

No viable constructor or deduction guide for deduction of template arguments of 'packaged_task'


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?


Solution

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