首页 > 解决方案 > 将函数传递给可变参数函数模板

问题描述

考虑以下函数模板:

template<typename RetType, typename... ArgTypes>
void foo0(std::function<RetType(ArgTypes...)> f) {}

template<typename RetType, typename ArgType>
void foo1(std::function<RetType(ArgType)> f) {}

以及以下功能:

void bar(int n) {}

为什么会出现以下情况:

 foo0<void, int>(bar);  // does not compile
 foo1<void, int>(bar);  // compiles fine

编译错误是(gcc-8 with C++17):

error: no matching function for call to 'foo0<void, int>(void (&)(int))'
   foo0<void, int>(bar);
                      ^
note: candidate: 'template<class RetType, class ... ArgTypes> void foo0(std::function<_Res(_ArgTypes ...)>)'
 void foo0(std::function<RetType(ArgTypes...)> f) {}
      ^~~~
note:   template argument deduction/substitution failed:
note:   mismatched types 'std::function<void(_ArgTypes ...)>' and 'void (*)(int)'
   foo0<void, int>(bar);

使用虚拟模板

template<typename T>
void bar(int n) {}

在 gcc-8 中可以foo0<void, int>(bar<int>);正常编译,但在 Apple LLVM 版本 10.0.0 (clang-1000.11.45.5) 中使用 clang 会出错。

铿锵的错误是

error: no matching function for call to 'foo0'
  foo0<void, int>(bar<int>);
  ^~~~~~~~~~~~~~~
note: candidate template ignored: could not match 'function<void (int, type-parameter-0-1...)>' against 'void (*)(int)'
void foo0(std::function<RetType(ArgTypes...)> f) {}

标签: c++templatesc++17variadic-templates

解决方案


为什么会出现以下情况 [?]

当你打电话时算一算

 foo0<void, int>(bar); // compilation error
 foo1<void, int>(bar); // compile

foo0()andfoo1()期望 a std::functionandbar是指向可以转换为 astd::function但不是 a的函数的指针std::function

在这种foo1()情况下,您显式了 bothRetTypeArgType模板参数,因此编译器可以转换bar为 astd::function<void(int)>并且一切顺利。

foo0()情况有所不同,因为模板参数ArgTypes...是一个可变参数,并且调用foo0<void, int>(bar)您并没有显式显示完整的ArgTypes...可变参数列表,而只是第一种类型。

如果我没记错的话,问题是编译器试图ArgTypes...bar参数中推断出其余部分,但bar不是,std::function所以编译器无法推断出其余部分ArgTypes...,所以错误。

我想

foo0<void, int>(std::function<void(int)>{bar});

或者干脆

foo0(std::function<void(int)>{bar});

或(仅限 C++17)也

foo0(std::function{bar});

应该编译因为,foo0()这样调用,函数接收到一个std::function,所以编译器可以完全推导出模板参数。

我不明白bar()带有虚拟模板参数的版本如何

foo0<void, int>(bar<int>);

可以用 g++-8 编译,我想这是一个 g++ 错误。


推荐阅读