Consider the following code:
#include<concepts>
template<typename>
void foo() { }
template<std::integral>
void foo() { }
template<>
void foo<bool>() { }
int main() { foo<bool>(); }
It compiles without issues under recent Clang and MSVC, but not GCC (godbolt link)
The build with GCC fails with:
error: ambiguous template specialization 'foo<bool>' for 'void foo()'
9 | void foo<bool>() { }
| ^~~~~~~~~
note: candidates are: 'template<class> void foo()'
3 | void foo() { }
| ^~~
note: 'template<class> requires integral< <template-parameter-1-1> > void foo()'
6 | void foo() { }
| ^~~
Which compiler is right? I'd say that GCC is wrong as there shouldn't be any ambiguity between a specialization through a concept (which keeps the code still generic) and an actual explicit specialization from the user which should always get priority.
In order to decide which of the two foo
function templates your explicit specialization refers to, template argument deduction according to [temp.deduct.decl] is performed and partial ordering of function templates is applied to find a unique best match.
In your case template argument deduction against both candidates will succeed, but partial ordering of templates should succeed to determine the second template as the better match, as it is more constrained than the first one. (per [temp.func.order]/6.4 and [temp.constr.order]/3.2).
So yes, I'd say GCC is wrong here. It doesn't seem to (fully) consider function template partial ordering.