编译器无法推断可变参数模板的模板参数
Compiler unable to deduce template arguments for variadic template
假设我想 partial function application 使范围广泛的功能符合单一签名。
例如,我可能想从双参数函数转到单参数函数,如下所示:
std::function<int(int, int)> doubleFoo = [](int i, int j) { return i + j; };
// Turn the function into a single-parameter function, using j = 5
std::function<int(int)> singleFoo = toSingleFoo(doubleFoo, 5);
因为我希望 toSingleFoo
处理第一个参数是 int
的任何单参数或多参数函数,所以我将其定义为可变参数模板函数:
template <typename... Args>
std::function<int(int i)> toSingleFoo(std::function<int(int, Args&&...)> multiFoo, Args&&... args)
{
auto singleFoo = [args](int i) { multiFoo(i, std::forward<Args>(args)...) };
return singleFoo;
}
但是,这会产生以下编译器错误(使用 Visual Studio 2017,版本 15.7.6):
error C2672: 'toSingleFoo': no matching overloaded function found
error C2784: 'std::function<int (int)> toSingleFoo(std::function<int(int,Args &&...)>,Args &&...)':
could not deduce template argument for 'std::function<int(int,Args &&...)>'
from 'std::function<int (int,int)>'
为什么编译器无法推断出模板参数,尽管在上面的示例中 int
作为第二个参数传递?
首先,您需要捕获 multiFoo
,以及捕获可变参数 args...
。
推论的问题似乎在 std::function
论证中。如果您只允许它从第二个参数中推导出 Args...
,推导将按预期进行。
要隐藏第一个参数的推导,只需将其放在身份模板中即可
template<typename T>
struct I { using type = T; };
那么你可以定义函数为
template <typename... Args>
std::function<int(int)> toSingleFoo(
typename I<std::function<int(int, Args&&...)>>::type multiFoo,
Args&&... args)
{
return [multiFoo, &args...] (int i) {
return multiFoo(i, std::forward<Args>(args)...);
};
}
然后使用它
int main() {
std::function<int(int, int)> doubleFoo = [](int i, int j) { return i + j; };
// Turn the function in a single-parameter function, using j = 5
std::function<int(int)> singleFoo1 = toSingleFoo(doubleFoo, 5);
std::cout << singleFoo1(3); // prints 8
std::function<int(int, int, int)> tripleFoo = [](int i, int j, int k) { return i * j * k; };
// Turn the function in a single-parameter function, using j = 2, k = 3
std::function<int(int)> singleFoo2 = toSingleFoo(tripleFoo, 2, 3);
std::cout << singleFoo2(4); // prints 24
}
假设我想 partial function application 使范围广泛的功能符合单一签名。
例如,我可能想从双参数函数转到单参数函数,如下所示:
std::function<int(int, int)> doubleFoo = [](int i, int j) { return i + j; };
// Turn the function into a single-parameter function, using j = 5
std::function<int(int)> singleFoo = toSingleFoo(doubleFoo, 5);
因为我希望 toSingleFoo
处理第一个参数是 int
的任何单参数或多参数函数,所以我将其定义为可变参数模板函数:
template <typename... Args>
std::function<int(int i)> toSingleFoo(std::function<int(int, Args&&...)> multiFoo, Args&&... args)
{
auto singleFoo = [args](int i) { multiFoo(i, std::forward<Args>(args)...) };
return singleFoo;
}
但是,这会产生以下编译器错误(使用 Visual Studio 2017,版本 15.7.6):
error C2672: 'toSingleFoo': no matching overloaded function found
error C2784: 'std::function<int (int)> toSingleFoo(std::function<int(int,Args &&...)>,Args &&...)':
could not deduce template argument for 'std::function<int(int,Args &&...)>'
from 'std::function<int (int,int)>'
为什么编译器无法推断出模板参数,尽管在上面的示例中 int
作为第二个参数传递?
首先,您需要捕获 multiFoo
,以及捕获可变参数 args...
。
推论的问题似乎在 std::function
论证中。如果您只允许它从第二个参数中推导出 Args...
,推导将按预期进行。
要隐藏第一个参数的推导,只需将其放在身份模板中即可
template<typename T>
struct I { using type = T; };
那么你可以定义函数为
template <typename... Args>
std::function<int(int)> toSingleFoo(
typename I<std::function<int(int, Args&&...)>>::type multiFoo,
Args&&... args)
{
return [multiFoo, &args...] (int i) {
return multiFoo(i, std::forward<Args>(args)...);
};
}
然后使用它
int main() {
std::function<int(int, int)> doubleFoo = [](int i, int j) { return i + j; };
// Turn the function in a single-parameter function, using j = 5
std::function<int(int)> singleFoo1 = toSingleFoo(doubleFoo, 5);
std::cout << singleFoo1(3); // prints 8
std::function<int(int, int, int)> tripleFoo = [](int i, int j, int k) { return i * j * k; };
// Turn the function in a single-parameter function, using j = 2, k = 3
std::function<int(int)> singleFoo2 = toSingleFoo(tripleFoo, 2, 3);
std::cout << singleFoo2(4); // prints 24
}