c++ 接受const char(&)[N]的函数模板比接受const T&的函数模板更专用吗?

kgqe7b3p  于 2024-01-09  发布在  其他
关注(0)|答案(1)|浏览(134)

我定义了两个版本的函数模板compare

  1. #include <cstring>
  2. using namespace std;
  3. // fist version
  4. template <size_t N, size_t M>
  5. int compare(const char (&a)[N], const char (&b)[M]) {
  6. return strcmp(a, b);
  7. }
  8. // second version
  9. template <typename T>
  10. int compare(const T &a, const T &b) {
  11. if (a < b) return -1;
  12. if (b < a) return 1;
  13. return 0;
  14. }
  15. int main() {
  16. const char *p1 = "dog", *p2 = "cat";
  17. compare(p1, p2); // call second version
  18. compare("dog", "cat"); // call second version?
  19. return 0;
  20. }

字符串
在使用c++11std的 CPP Primer(5th edition) 一书中,作者说compare(p1, p2)将调用第二个版本的模板,因为没有办法将指针转换为数组的引用。compare("dog", "cat")将调用compare的第二个版本,因为它比第一个版本更专用。
然而,当我运行这段代码时,我得到一个编译器错误:
调用重载的“compare(const char [4],const char [4])"不明确
然后,我将compare("dog", "cat")更改为compare("dog", "cats"),它可以调用第二个版本的模板,没有问题。
为什么ab具有相同的长度会导致二义性?

67up9zun

67up9zun1#

**tldr;**这是CWG 2160,它指出当前的措辞没有说明/指定在 * 部分排序 * 期间冲突的推导类型是否应该无效或忽略(有效)。MSVC似乎忽略了由于调用compare("dog", "cat");引起的冲突并接受程序,而GCC和Clang似乎拒绝了在部分排序期间冲突的推导类型并拒绝程序。

用例1:调用compare(p1,p2);

版本1是专门为const char数组编写的。对于所有其他类型,第二个版本是可行的选择。因此,对于第一个调用compare(p1, p2),应该选择第二个版本compare(const T &a, const T &b),因为第一个版本compare(const char (&a)[N], const char (&b)[M])甚至不可行

Case 2:用于调用compare(“dog”,“cat”);

现在来看第二个调用compare("dog", "cat")。这里在 * 部分排序 * 期间,当版本1的转换模板与原始模板版本2匹配时冲突类型是为T推导的。现在,当前的措辞并没有指定这种冲突行为应该被忽略还是接受。MSVC似乎忽略了冲突的推导类型,而GCC和Clang似乎拒绝了它。这是仍然是一个悬而未决的问题。如果冲突类型被忽略,那么这个匹配成功,而如果冲突类型不被忽略,那么这个匹配失败。所以在第一种情况下有两种可能性。
再次进行相同的过程,即,尝试将第二模板的变换类型与原始模板版本1匹配失败。
本质上,有 * 两种可能性 * 取决于在部分排序期间是否忽略冲突类型:

  • 如果要忽略它们,那么版本1更专业,MSVC接受程序是正确的。
  • 如果它们不被忽略,那么它们都不是更特殊的,程序对于调用compare("dog", "cat")来说将是病态的。

GCC rejects call to more specialized const char array version with string literal.

展开查看全部

相关问题