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

Enr*_*lis 5 c++ sfinae language-lawyer enable-if function-templates-overloading

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

#include <utility>

template<typename T, typename = void>
struct A {};

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

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

int main() {
  A<std::pair<int, int>> x;
  f(x);
}
Run Code Online (Sandbox Code Playgroud)

错误很明显

uffa.cpp: In function ‘int main()’:                                                                                                                                                                                                                           
uffa.cpp:22:4: error: call of overloaded ‘f(A<std::pair<int, int> >&)’ is ambiguous                                                                                                                                                                           
   22 |   f(x);                                                                                                                                                                                                                                                
      |   ~^~~                                                                                                                                                                                                                                                 
uffa.cpp:10:6: note: candidate: ‘void f(A<std::pair<_T1, _T2> >) [with T = int; U = int]’                                                                                                                                                                     
   10 | void f(A<std::pair<T,U>>) {}                                                                                                                                                                                                                           
      |      ^                                                                                                                                                                                                                                                 
uffa.cpp:18:6: note: candidate: ‘void f(A<std::pair<int, U>, typename std::enable_if<is_same_v<int, U>, void>::type>) [with U = int; typename std::enable_if<is_same_v<int, U>, void>::type = void]’                                                          
   18 | void f(A<std::pair<int,U>, std::enable_if_t<std::is_same_v<int,U>>>) {}                                                                                                                                                                                
      |      ^
Run Code Online (Sandbox Code Playgroud)

但我不明白为什么int在第二个重载中作为固定模板参数不会使它更专业化。毕竟,如果我, std::enable_if_t<std::is_same_v<int,U>>从中删除,那么它首选。

Hol*_*Cat 1

尽管这是,但我将提供一个外行的解释。

pair是的,第二个重载修复了as的第一个参数int,而第一个重载则没有。

但是,另一方面,第一个重载修复了as的第二个参数Avoid,而第二个重载则没有。

您的功能相当于:

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>>) {}
Run Code Online (Sandbox Code Playgroud)

因此,它们中没有一个比另一个更专业。


如果您更多地使用传统的 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>>) {}
Run Code Online (Sandbox Code Playgroud)

或者C++20概念:

template <std::same_as<int> U>
void f(A<std::pair<int,U>>) {}
Run Code Online (Sandbox Code Playgroud)