这个问题是十年前的另一个问题的延伸:
#include<functional>
template <typename ReturnType, typename... ArgumentTypes>
struct Caller
{
static void Call(std::function<ReturnType(ArgumentTypes...)>);
};
template <typename ReturnType, typename...ArgumentTypes>
void Call(std::function<ReturnType(ArgumentTypes...)>f);
int main()
{
Caller<void>::Call([]() {});//Well-formed
Call<void>({[]() {}});//Well-formed
Call<void>([]() {});//Ill-formed
}
代码在
std::function
签名中提供了三种方法来扩展模板参数包。前两个已经过测试,格式良好并且可以编译;最后一个问题与旧问题相同,因此格式不正确。问题是,前两种方法是如何绕过原问题和最后一种方法中导致编译失败的问题的呢?
对于 struct
Caller
,所有模板参数都会被传递(仅 void
和空包),因为没有部分 CTAD。 Lambda可以转换成std::function<void()>
,所以就可以了
对于函数模板
Call
,只要参数只是第一个,仍然可能会发生推论。
lambda 不是
std::function
,因此不能推导为 std::function<Ret(Args...)>
,因此第三种方法失败。
对于第二个,额外的
{..}
(没有类型)“强制”构造一个std::function
,从std::function{[](){}}
开始,由于std::function<void()>
的CTAD推导为
std::function
。
那么 Call
可以将模板参数推导出为 void
和空包。