是什么导致这两个函数模板之间的重载失败?
What makes the overload fail between these two function templates?
下面是一个非常简短的例子。
#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);
}
错误很明显
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>>>) {}
| ^
但我不明白为什么将 int
作为第二个重载中的固定模板参数并不能使其更加专业化。毕竟,如果我从中删除 , std::enable_if_t<std::is_same_v<int,U>>
,那么它 是 首选。
尽管这是language-lawyer,但我将提供一个外行的解释。
是的,第二个重载将 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>>) {}
所以其中 none 个比另一个更专业。
如果您使用更多的常规 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>>) {}
或C++20概念:
template <std::same_as<int> U>
void f(A<std::pair<int,U>>) {}
下面是一个非常简短的例子。
#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);
}
错误很明显
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>>>) {}
| ^
但我不明白为什么将 int
作为第二个重载中的固定模板参数并不能使其更加专业化。毕竟,如果我从中删除 , std::enable_if_t<std::is_same_v<int,U>>
,那么它 是 首选。
尽管这是language-lawyer,但我将提供一个外行的解释。
是的,第二个重载将 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>>) {}
所以其中 none 个比另一个更专业。
如果您使用更多的常规 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>>) {}
或C++20概念:
template <std::same_as<int> U>
void f(A<std::pair<int,U>>) {}