为什么使用 std::function 回调的可变参数模板推导失败?
Why does template argument deduction failed with variadic template parameters of a std::function callback?
让我们考虑以下功能:
// run_cb_1(): Explicitly defined prototype
void run_cb_1(const std::function<void(int)> & callback, int p)
{
callback(p);
}
// run_cb_2(): One template parameter
template <typename T>
void run_cb_2(const std::function<void(T)> & callback, const T & t)
{
callback(t);
}
// run_cb_3(): Variable number of template parameters
template <typename ... Args>
void run_cb_3(const std::function<void(Args...)> & callback, const Args & ... args)
{
callback(args...);
}
现在如果我想按如下方式使用这些功能:
int main()
{
auto f = [](int a){
std::cout << a << '\n';
};
run_cb_1(f, 5); // OK
run_cb_2(f, 5); // KO --> I understand why
run_cb_2<int>(f, 5); // OK
run_cb_3(f, 5); // KO --> I understand why
run_cb_3<int>(f, 5); // KO --> I don't understand why...
return 0;
}
我得到一个 "no matching function call" 与 run_cb_2()
和 run_cb_3()
而它与 run_cb_1()
.[=23 完美配合=]
我认为它的行为符合预期,因为我没有提供模板参数的类型(因为它不能像 run_cb_1()
那样简单地推断出来)。
但是指定模板类型可以解决 run_cb_2()
的问题(如我所料),但不能解决 run_cb_3()
.
的问题
我知道我可以通过明确声明 f
为 来解决它:
std::function<void(int)> f = [](int a){
std::cout << a << '\n';
};
或 通过将 f 传递为:
run_cb_2(std::function<void(int)>(f), 5);
run_cb_3(std::function<void(int)>(f), 5);
我的问题是:为什么即使明确指定模板类型,模板参数推导也会因 run_cb_3()
(使用可变模板参数)而失败?
很明显我错过了一些东西(也许是基本的)但我不知道是什么。
任何帮助将不胜感激。
失败的原因是编译器可以使用的类型不止一种。当你做
run_cb_2<int>(f, 5);
编译器查看run_cb_2
,发现只有一个模板参数。由于您已经提供它跳过推导阶段并消除 run_cb_2<int>
.
有
run_cb_3<int>(f, 5);
你在另一条船上。 run_cb_3
有一个可变模板参数,这意味着仅提供 int
不足以跳过推导。您指定了第一个参数,但可能还有更多参数,因此它会进入参数推导阶段来弄清楚。这意味着它会检查 callback
以确保它推导的内容与它为 args
推导的内容相匹配。由于 lambda 不是 std::function
,因此无法从中推断出 Args...
。一旦发生这种情况,编译器就会停止并发出错误。
对于run_cb_3<int>
,您没有明确提供完整的Args...
,只是第一种;它可能还有其他。
例如在std::make_unique
:
等函数中使用
template <class T, class... Args>
std::unique_ptr<T> make_unique(Args&&... args);
和
std::make_unique<MyObj>(var1, var2); // T = MyObj
// Args... = [decltype((var1)), decltype((var2))]
从参数中推导出额外的参数。
要强制求值,您可以使用:
(&run_cb_3<int>)(f, 5); // OK
让我们考虑以下功能:
// run_cb_1(): Explicitly defined prototype
void run_cb_1(const std::function<void(int)> & callback, int p)
{
callback(p);
}
// run_cb_2(): One template parameter
template <typename T>
void run_cb_2(const std::function<void(T)> & callback, const T & t)
{
callback(t);
}
// run_cb_3(): Variable number of template parameters
template <typename ... Args>
void run_cb_3(const std::function<void(Args...)> & callback, const Args & ... args)
{
callback(args...);
}
现在如果我想按如下方式使用这些功能:
int main()
{
auto f = [](int a){
std::cout << a << '\n';
};
run_cb_1(f, 5); // OK
run_cb_2(f, 5); // KO --> I understand why
run_cb_2<int>(f, 5); // OK
run_cb_3(f, 5); // KO --> I understand why
run_cb_3<int>(f, 5); // KO --> I don't understand why...
return 0;
}
我得到一个 "no matching function call" 与 run_cb_2()
和 run_cb_3()
而它与 run_cb_1()
.[=23 完美配合=]
我认为它的行为符合预期,因为我没有提供模板参数的类型(因为它不能像 run_cb_1()
那样简单地推断出来)。
但是指定模板类型可以解决 run_cb_2()
的问题(如我所料),但不能解决 run_cb_3()
.
我知道我可以通过明确声明 f
为 来解决它:
std::function<void(int)> f = [](int a){
std::cout << a << '\n';
};
或 通过将 f 传递为:
run_cb_2(std::function<void(int)>(f), 5);
run_cb_3(std::function<void(int)>(f), 5);
我的问题是:为什么即使明确指定模板类型,模板参数推导也会因 run_cb_3()
(使用可变模板参数)而失败?
很明显我错过了一些东西(也许是基本的)但我不知道是什么。
任何帮助将不胜感激。
失败的原因是编译器可以使用的类型不止一种。当你做
run_cb_2<int>(f, 5);
编译器查看run_cb_2
,发现只有一个模板参数。由于您已经提供它跳过推导阶段并消除 run_cb_2<int>
.
有
run_cb_3<int>(f, 5);
你在另一条船上。 run_cb_3
有一个可变模板参数,这意味着仅提供 int
不足以跳过推导。您指定了第一个参数,但可能还有更多参数,因此它会进入参数推导阶段来弄清楚。这意味着它会检查 callback
以确保它推导的内容与它为 args
推导的内容相匹配。由于 lambda 不是 std::function
,因此无法从中推断出 Args...
。一旦发生这种情况,编译器就会停止并发出错误。
对于run_cb_3<int>
,您没有明确提供完整的Args...
,只是第一种;它可能还有其他。
例如在std::make_unique
:
template <class T, class... Args>
std::unique_ptr<T> make_unique(Args&&... args);
和
std::make_unique<MyObj>(var1, var2); // T = MyObj
// Args... = [decltype((var1)), decltype((var2))]
从参数中推导出额外的参数。
要强制求值,您可以使用:
(&run_cb_3<int>)(f, 5); // OK