std :: function中的可变参数模板参数匹配

时间:2014-05-27 22:34:10

标签: c++ templates c++11 variadic-templates

我有以下代码:

#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,那么实际上func需要{{1} }}作为参数),然后std::function<Return(Params)>中的注释行按需运行。有什么想法吗?

1 个答案:

答案 0 :(得分:11)

  

我不明白为什么行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是单一类型,而不是零或更多类型的包,所以当你说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");

我只给出了两个参数的显式模板参数,因此仍然必须推导出第三个参数。

当你有一个可变参数模板时,可能会有任何数量的其他参数被推断出来。