在 C++20 中,是否不再允许在 std 中对程序定义类型的函数模板进行特化?

Will specialization of function templates in std for program-defined types no longer be allowed in C++20?

引自cppreference.com

Adding template specializations

It is allowed to add template specializations for any standard library |class (since C++20)| template to the namespace std only if the declaration depends on at least one program-defined type and the specialization satisfies all requirements for the original template, except where such specializations are prohibited.

这是否意味着,从 C++20 开始,将不再允许将函数模板的特化添加到用户定义类型的 std 命名空间?如果是这样,这意味着许多现有代码都可以破坏,不是吗? (在我看来,这是一种 "radical" 的改变。)此外,它会向此类代码中注入未定义的行为,这不会触发编译错误(希望会出现警告)。

没那么激进。此更改基于 this paper from Walter E. Brown。该论文相当深入地探讨了基本原理,但最终归结为:

  1. 功能模板的专业化作为一个定制点是相当差的。超载和 ADL 在这方面要好得多。论文中还讨论了其他自定义点。
  2. 标准库已经不太依赖这个糟糕的定制点了。
  3. 所进行的措辞更改实际上允许在明确允许的地方将整个声明添加到命名空间 std(而不仅仅是专门化)。所以现在有 更好 个定制点。

鉴于#1 和#2,现有代码不太可能被破坏。或者至少,这还不足以成为一个主要问题。过去使用 autoregister 的代码也 "broke",但极少量的 C++ 代码并没有阻止进步。

现在看起来确实是这样。以前 [namespace.std] 包含

A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.

同时 the current draft states

Unless explicitly prohibited, a program may add a template specialization for any standard library class template to namespace std provided that (a) the added declaration depends on at least one program-defined type and (b) the specialization meets the standard library requirements for the original template.

强调我的

而且看起来 Walter E. Brown 的论文 Thou Shalt Not Specialize std Function Templates! 对此负责。他在其中详细说明了应该更改的一些原因,例如:

  • Herb Sutter: “specializations don’t participate in overloading. [...] If you want to customize a function base template and want that customization to participate in overload resolution (or, to always be used in the case of exact match), make it a plain old function, not a specialization. And, if you do provide overloads, avoid also providing specializations.”
  • David Abrahams: “it’s wrong to use function template specialization [because] it interacts in bad ways with overloads. [...] For example, if you specialize the regular std::swap for std::vector<mytype>&, your specialization won’t get chosen over the standard’s vector specific swap, because specializations aren’t considered during overload resolution.”
  • Howard Hinnant: “this issue has been settled for a long time. . . . Disregard Dave’s expert opinion/answer in this area at your own peril.”
  • Eric Niebler: “[because of] the decidedly wonky way C++ resolves function calls in templates. . . , [w]e make an unqualified call to swap in order to find an overload that might be defined in [...] associated namespaces[...] , and we do using std::swap so that, on the off-chance that there is no such overload, we find the default version defined in the std namespace.”
  • High Integrity C++ Coding Standard: “Overload resolution does not take into account explicit specializations of function templates. Only after overload resolution has chosen a function template will any explicit specializations be considered.”