You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何GCC/Clang下packaged_task模板参数推导失败?如何修复?

问题描述

以下代码在Windows平台MSVC 2022编译器、C++17模式下可正常编译,但在Linux平台GCC 11.3和Clang 16.0编译器中编译失败。

测试代码

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

GCC编译错误信息

/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’

Clang编译错误信息

/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
原因分析
  • C++17标准中,std::packaged_task并未提供从函数指针自动推导模板签名参数的推导指南。
  • MSVC 2022实现了非标准扩展,允许直接从函数指针推导packaged_task的模板参数;而GCC和Clang严格遵循C++标准,未实现该扩展,因此无法推导_Signature模板参数,导致编译失败。
修复方案

以下两种方式均可实现跨编译器兼容:

方式一:显式指定packaged_task的模板签名

明确指定packaged_task的函数签名格式(返回类型(参数类型列表)),让编译器无需推导:

template <class T>
T parallel_accumulate(const std::vector<T>& v)
{
  // 显式指定签名:T(const T*, const T*, T)
  packaged_task<T(const T*, const T*, T)> pt0{accumulate<const T*, T>};
  packaged_task<T(const T*, const T*, T)> pt1{accumulate<const T*, T>};

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

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

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

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

方式二:用lambda包裹调用(更简洁)

通过lambda包裹accumulate调用,利用C++17对lambda的推导支持,让编译器自动推导packaged_task的模板参数:

template <class T>
T parallel_accumulate(const std::vector<T>& v)
{
  packaged_task pt0{[](const T* first, const T* last, T init) {
    return accumulate(first, last, init);
  }};
  packaged_task pt1{[](const T* first, const T* last, T init) {
    return accumulate(first, last, init);
  }};

  auto f0 = pt0.get_future();
  auto f1 = pt1.get_future();

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

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

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

内容的提问来源于stack exchange,提问作者bobeff

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 02:07:07