【问题标题】:Why doesn't parameter pack expand to correct type?为什么参数包不扩展为正确的类型?
【发布时间】:2021-07-29 09:10:14
【问题描述】:

我有一段有点做作的代码:

#include <functional>

template <typename... ARGs>
auto construct1(std::function<void(ARGs...)> p, const ARGs &...args) {}

template < typename... ARGs>
auto construct2(std::function<void(int)>     p, const ARGs &...args) {}

int main() {
    auto p = [](int) {};
    construct1<int>(p, 0);
    construct2<int>(p, 0);
    return 0;
}

为什么编译器在第一种情况下难以计算出ARGs... = { int }?如果我通过在签名中使用std::function&lt;void(int)&gt; 来协助编译器(第二种情况),则代码可以编译。在这两种情况下,编译器都可以轻松推断出const ARGs&amp;... 应该是const int&amp;。使用 C++17。

海合会:

main.cpp: In function ‘int main()’:
main.cpp:11:25: error: no matching function for call to ‘construct1<int>(main()::<lambda(int)>&, int)’
   11 |     construct1<int>(p, 0);
      |                         ^
main.cpp:4:6: note: candidate: ‘template<class ... ARGs> auto construct1(std::function<void(ARGs ...)>, const ARGs& ...)’
    4 | auto construct1(std::function<void(ARGs...)> p, const ARGs &...args) {}
      |      ^~~~~~~~~~
main.cpp:4:6: note:   template argument deduction/substitution failed:
main.cpp:11:25: note:   ‘main()::<lambda(int)>’ is not derived from ‘std::function<void(ARGs ...)>’
   11 |     construct1<int>(p, 0);
      |  

叮当声:

main.cpp:11:5: error: no matching function for call to 'construct1'
    construct1<int>(p, 0);
    ^~~~~~~~~~~~~~~
main.cpp:4:6: note: candidate template ignored: could not match 'function<void (int, type-parameter-0-0...)>' against '(lambda at main.cpp:10:14)'
auto construct1(std::function<void(ARGs...)> p, const ARGs &...args) {}
     ^
1 error generated.

【问题讨论】:

标签: c++ templates variadic-templates parameter-pack


【解决方案1】:

问题是,construct1 正在使用 std::function,但您正在传递 lambda。当你将参数设为std::function&lt;void(ARGs...)&gt; 类型时,执行template argument deduction 以在函数参数p 上推导出ARGs(即使模板参数包是用template arguments 显式指定的,如果有,它可以通过模板参数推导扩展附加参数),因为隐式转换不会在推论中考虑。

类型推导不考虑隐式转换(除了上面列出的类型调整):这是重载解析的工作,稍后会发生。

您可以使用std::type_identity(C++20 起)将p 排除在推论之外(参见non-deduced contexts),例如

template <typename... ARGs>
auto construct1(std::function<void(std::type_identity_t<ARGs>...)> p, const ARGs &...args) {}
//                                 ^^^^^^^^^^^^^^^^^^^^^    ^

LIVE


PS:在 C++20 之前,您可以轻松地赢取 type_identity 为:

template< class T >
struct type_identity {
    using type = T;
};
template< class T >
using type_identity_t = typename type_identity<T>::type;

【讨论】:

  • 当显式指定模板参数时,为什么要执行模板参数推导?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-14
  • 1970-01-01
相关资源
最近更新 更多