C++ 是什么导致这两个函数模板之间的重载失败?

C++ 是什么导致这两个函数模板之间的重载失败?,c++,language-lawyer,sfinae,enable-if,function-templates-overloading,C++,Language Lawyer,Sfinae,Enable If,Function Templates Overloading,下面是一个非常简短的例子 #包括 模板 结构A{}; 模板 无效f(A){} 模板 无效f(A){} int main(){ A x; f(x); } 错误很明显 uffa.cpp:在函数“int main()”中: uffa.cpp:22:4:错误:重载“f(A&)”的调用不明确 22 | f(x); | ~^~~

下面是一个非常简短的例子

#包括
模板
结构A{};
模板
无效f(A){}
模板
无效f(A){}
int main(){
A x;
f(x);
}
错误很明显

uffa.cpp:在函数“int main()”中:
uffa.cpp:22:4:错误:重载“f(A&)”的调用不明确
22 | f(x);
|   ~^~~                                                                                                                                                                                                                                                 
注释:候选者:'void f(A)[带T=int;U=int]'
10 |无效f(A){}
|      ^                                                                                                                                                                                                                                                 
cpp:18:6:注:候选者:“void f(A)[with U=int;typename std::enable_if::type=void]”
18 |无效f(A){}
|      ^
但是我不明白为什么在第二个重载中使用
int
作为固定模板参数并不能使它更专业化。毕竟,如果我从中删除
,std::enable_if_t
,那么它是首选的。

尽管如此,我还是要提供一个外行解释

是的,第二个重载将
pair
的第一个参数固定为
int
,而第一个参数不固定

但是,另一方面,第一个重载将
A
第二个参数固定为
void
,而第二个重载则没有

您的功能等同于以下功能:

template <typename T, typename U>
void f(A<std::pair<T, U>, void>) {}

template <typename U>
void f(A<std::pair<int,U>, blah-blah<U>>) {}
模板
无效f(A){}
模板
无效f(A){}
所以没有一个比另一个更专业


如果您更多地使用传统的SFINAE,代码将起作用:

template<typename U, std::enable_if_t<std::is_same_v<U, int>, std::nullptr_t> = nullptr>
void f(A<std::pair<int,U>>) {}
模板
无效f(A){}
或C++20概念:

template <std::same_as<int> U>
void f(A<std::pair<int,U>>) {}
模板
无效f(A){}

请参阅。这(偏序规则)适用,不管您是否明确指定了
int
,因为模板函数是首先合成的,并且两者都是可行的。谢谢@CodyGray,我以前遇到过这个问题,从未理解过这个问题。更具体地说,您的链接中包含了此示例:。“这种类型推断只考虑有显式调用参数的参数,有些参数被忽略了”我可以高兴地说,在不损害我不存在的[]徽章的情况下,我在现实世界中从未遇到过这种情况,如果我曾经遇到过,我更愿意将代码重写为更明显、更可读的代码。模板非常棒,我使用它们的效果非常好,但要记住重载解析的细节。。。meh,没人有时间这么做。@CodyGray所以我的代码片段中的
f
的两个定义是两个模板,分别独立地进行替换(就像我删除其中一个并编译,然后对另一个做相同的操作一样)而只有板材替代才能同时考虑这两个因素来决定选择哪一个?但是,删除
enable\u if
如何解决这个问题呢?您没有按照SFINAE的正常方式使用
enable\u if
;实际上,您将其添加为普通参数,而不是模板类型参数。如果你这样做,我想结果会更符合你的期望。(请注意,我修改了您的函数以返回
int
,而不是
void
,这样我们就可以看到编译器选择了哪一个。这并不会改变重载解析或其他语义,因为这两个函数的变化是相同的。)第一个重载修复了
std::pair
的某些内容,哪一个是
a
的模板参数,而第二个修复了
a
本身的某些内容?我想答案是这两件事对专业化的影响程度相同,但标准的哪一部分说明了/强调了这一点?这可能是一个愚蠢的问题,但对我来说,在语言律师这件事上很容易有点偏执。@Enlico编译器不会判断哪个不同的专业“更重要”。对于X比Y更专业的,它必须以完全相同的方式进行专门化,然后是一些。类似的规则适用于C++中的任何地方。对于类模板专门化,对于C++20约束等,它必须以完全相同的方式专门化,然后是一些:您能澄清一下吗?我想我的英语是在插手:/@Enlico我不是母语人士,所以可能这不是最好的措辞。假设您有
模板