c++language-lawyertemplate-specializationc++-conceptsexplicit-specialization

Ambiguous template specialization with concepts and real types: which compiler is right?


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.


Solution

  • 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.