C++ 使用“std::function”和以前推导的模板参数替换失败-为什么?
考虑以下代码:C++ 使用“std::function”和以前推导的模板参数替换失败-为什么?,c++,c++11,templates,language-lawyer,template-argument-deduction,C++,C++11,Templates,Language Lawyer,Template Argument Deduction,考虑以下代码: template <typename> struct S { }; void g(S<int> t); template <typename T> void f(T, std::function<void(S<T>)>); 我得到以下错误: 错误:调用“f”时没有匹配的函数 f(0,g); ^ 注意:已忽略候选模板:无法匹配 “功能” 针对“无效(*)(S)”的 void f(T,std::function);
template <typename>
struct S { };
void g(S<int> t);
template <typename T>
void f(T, std::function<void(S<T>)>);
我得到以下错误:
错误:调用“f”时没有匹配的函数
f(0,g);
^
注意:已忽略候选模板:无法匹配
“功能”
针对“无效(*)(S)”的
void f(T,std::function);
^
虽然我知道通常不能推断std::function
参数的类型,因为它是非推断上下文
在这种情况下,可以首先通过传递的参数0
推导T
,然后将其替换为std::function
,得到std::function
我希望在推导T=int
之后,编译器将替换签名中的所有T
,然后尝试使用参数g
构造std::function
参数
为什么不是这样?我认为替换/扣除发生的顺序与此有关,但我想看看相关的标准措辞
附加问题:这是一个在未来的标准中可能会改变的东西,同时保留向后兼容性,还是有一个根本原因导致这种替代不起作用
虽然我知道std::function参数的类型通常不能推断,因为它是一个未推断的上下文
这不是一个非推断的上下文。恰恰相反。由于尝试对std::function
的参数进行推断,但该参数不是std::function
,因此推断失败。从函数参数中推断模板参数必须与所有函数参数一致。如果其中一个失败了,那么它就完全失败了
[临时扣减类型]
在某些情况下,使用一组单独的
类型P和A,在其他情况下,将有一组相应的
类型P和A。每个P/A对的类型扣减是独立进行的,
然后合并推导出的模板参数值。如果类型
不能对任何P/A对进行扣减,或者如果对任何P/A对进行扣减
推断会导致多个可能的推断值集,或者
不同的对产生不同的推导值,或者如果有模板
参数既不是推导的,也不是显式指定的,模板
论证推理失败
将第二个函数参数的类型转换为非推断上下文实际上是克服错误的方法
#include <functional>
template<typename T>
struct type_identity {
using type = T;
};
template <typename>
struct S { };
void g(S<int> ) {}
template <typename T>
void f(T, typename type_identity<std::function<void(S<T>)>>::type) {}
int main() {
f(0, g);
}
#包括
模板
结构类型标识{
使用类型=T;
};
模板
结构S{};
无效g(S){}
模板
void f(T,typename type_identity::type){}
int main(){
f(0,g);
}
T
是从第一个函数参数成功推导出来的,没有什么可以推导的了。因此,这个决定被认为是成功的
虽然我知道通常不能推断std::function
参数的类型,因为它是非推断上下文,但在这种情况下,可以首先通过传递的参数0
推断t
事实并非如此T
在这种情况下是可以推断的。如果您将代码更改为
template <typename T>
void f(std::function<void(S<T>)>);
int main()
{
f(std::function<void(S<int>)>(g));
}
模板
void f(std::function);
int main()
{
f(std::function(g));
}
代码将被编译并且T
被正确推导
您的问题是,您正在将一个对象传递给它无法从中提取
t
的函数。当编译器试图推断T
时,它不会对函数参数进行任何转换。这意味着您有一个int
和一个函数作为传递给该函数的类型。它从0
中获取int
,然后尝试从您在第二个参数中传递的std::function
中获取类型,但是由于您没有传递std::function
,因此无法提取t
,因此,您会得到一个错误。这里没有std::function
或函数指针,情况也是如此,简化一点:您仍然可以使用模板void f(T,std::identity\u type\T)
@Jarod42是否std::identity\u type\T
进行标准化?@MaxLanghof
#include <functional>
template<typename T>
struct type_identity {
using type = T;
};
template <typename>
struct S { };
void g(S<int> ) {}
template <typename T>
void f(T, typename type_identity<std::function<void(S<T>)>>::type) {}
int main() {
f(0, g);
}
template <typename T>
void f(std::function<void(S<T>)>);
int main()
{
f(std::function<void(S<int>)>(g));
}