概念和实际类型的模糊模板专业化:哪个编译器是正确的?

Jea*_*ier 6 c++ template-specialization language-lawyer explicit-specialization c++-concepts

考虑以下代码:

#include<concepts>

template<typename>
void foo() { }

template<std::integral> 
void foo() { }

template<> 
void foo<bool>() { }

int main() { foo<bool>(); }
Run Code Online (Sandbox Code Playgroud)

它在最近的 Clang 和 MSVC 下编译没有问题,但在 GCC 下编译没有问题(godbolt 链接

使用 GCC 构建失败并显示:

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

哪个编译器是正确的?我想说 GCC 是错误的,因为通过概念进行的专业化(这使代码仍然通用)和来自用户的实际显式专业化之间不应该有任何歧义,用户应该始终获得优先权。

use*_*522 6

为了确定您的显式专业化引用了两个函数模板中的哪一个,将执行根据[temp.deduct.decl]foo的模板参数推导,并应用函数模板的部分排序来查找唯一的最佳匹配。

在您的情况下,针对两个候选者的模板参数推导将成功,但模板的部分排序应该成功确定第二个模板为更好的匹配,因为它比第一个模板受到更多限制。(根据[temp.func.order]/6.4[temp.constr.order]/3.2)。

所以,是的,我想说海湾合作委员会在这里是错误的。它似乎没有(完全)考虑函数模板部分排序。