函数中的可变模板参数匹配

variadic templates parameter matching in std::function

本文关键字:参数 函数      更新时间:2023-10-16

我有以下代码:

#include <iostream>
#include <functional>
template<typename Return, typename... Params>
void func(std::function<Return(Params... )> x) {}
void f(double) {}
int main() {
    //func<void, double>(f); // compile error here in the variadic case
    func(std::function<void(double)>(f));
}
我有两个问题:

1。我不明白为什么func<void, double>(f);行给我一个编译错误

/Users/vlad/minimal.cpp:10:5: error: no matching function for call to 'func'
    func<void, double>(f); // compile error here in the variadic case
    ^~~~~~~~~~~~~~~~~~
/Users/vlad/minimal.cpp:5:6: note: candidate template ignored: could not match 'function<void (double, type-parameter-0-1...)>' against 'void (*)(double)'
void func(std::function<Return(Params... )> x) {}
     ^
1 error generated.

然而,如果我将参数f转换为std::function(如未注释的行),它可以工作。

2。最令人困惑的问题是,如果我使用func的非可变版本(即只是用typename替换typename...,因此实际上funcstd::function<Return(Params)>作为参数),那么main中的注释行就可以按需工作。知道为什么吗?

我不明白为什么func<void, double>(f);行给我一个编译错误

编译器不知道你想让Params 恰好是 double,它认为你可能想让它推断出一个包含更多元素的包,比如double, int, void*, chardouble, double, double或其他类型的包,它不知道如何从参数f中推断出这一点。

理论上,std::function的其他专门化可以从f构造,这将允许编译器为Params推断出一个不止一种类型的包(如果没有实例化 std::function的所有可能的专门化并测试它们,它无法知道这是不是真的,这是不可行的。

然而,如果我将参数f强制转换为std::function(如未注释行),它可以工作。

因为现在编译器能够正确地推导出Params

最令人困惑的问题是,如果我使用func的非可变版本[…],那么main中的注释行就能正常工作。知道为什么吗?

因为现在编译器知道Params是单一类型,而不是0个或多个类型的包,所以当你说func<void, double>时,它知道Paramsdouble,而不是double, int, void*, char或其他参数包。

编辑回答你的评论,考虑一下:

template<typename T, typename U, typename V>
int func(T t, U u, V v)
{ return 0; }
int i = func<int, char>(1, '2', "three");

我只为其中两个形参给出了显式的模板实参,因此第三个形参仍然必须推导出来。

当你有一个可变的模板时,可以有任意数量的其他待推导的形参