接受 const char(&)[N] 的函数模板是否比接受 const T& 的函数模板更专业?

fan*_*rin 7 c++ function-templates overload-resolution compiler-bug

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

\n
#include <cstring>\n\nusing namespace std;\n\n// fist version\ntemplate <size_t N, size_t M>\nint compare(const char (&a)[N], const char (&b)[M]) {\n    return strcmp(a, b);\n}\n\n// second version\ntemplate <typename T>\nint compare(const T &a, const T &b) {\n    if (a < b) return -1;\n    if (b < a) return 1;\n    return 0;\n}\n\nint main() {\n    const char *p1 = "dog", *p2 = "cat";\n    compare(p1, p2); // call second version\n    compare("dog", "cat"); // call second version?\n\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在使用c++11std的CPP Primer(第5版)一书中,作者说compare(p1, p2)将调用第二版模板,因为没有办法将指针转换为对数组的引用。将compare("dog", "cat")调用第二个版本,compare因为它比第一个版本更专业。

\n

但是,当我运行此代码时,出现编译器错误:

\n
\n

重载 \xe2\x80\x98compare(const char [4], const char [4])\xe2\x80\x99 的调用不明确

\n
\n

然后我改成compare("dog", "cat")compare("dog", "cats"),就可以毫无问题地调用第二个版本模板了。

\n

为什么ab具有相同的长度会导致歧义?

\n

use*_*570 10

太棒了;这是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])


情况2:对于调用compare("dog", "cat");

现在进行第二次通话compare("dog", "cat")。这里,在部分排序期间,当将版本 1 的转换模板与原始模板版本 2 进行匹配时,会推导出冲突T类型。现在,当前的措辞并未指定是否应忽略或接受这种冲突行为。MSVC 似乎忽略了冲突的推导类型,而 GCC 和 Clang 似乎拒绝它。这仍然是一个悬而未决的问题。如果冲突类型被忽略,则匹配成功;如果冲突类型不被忽略,则匹配失败。因此,第一种情况有两种可能性。

再次执行相同的过程,即尝试将第二个模板的转换类型与原始模板版本 1 匹配失败。


本质上,根据部分排序期间是否忽略冲突类型,有两种可能性:

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

GCC 拒绝使用const char字符串文字调用更专门的数组版本。