我定义了两个版本的函数模板compare
:
#include <cstring>
using namespace std;
// fist version
template <size_t N, size_t M>
int compare(const char (&a)[N], const char (&b)[M]) {
return strcmp(a, b);
}
// second version
template <typename T>
int compare(const T &a, const T &b) {
if (a < b) return -1;
if (b < a) return 1;
return 0;
}
int main() {
const char *p1 = "dog", *p2 = "cat";
compare(p1, p2); // call second version
compare("dog", "cat"); // call second version?
return 0;
}
字符串
在使用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")
,它可以调用第二个版本的模板,没有问题。
为什么a
和b
具有相同的长度会导致二义性?
1条答案
按热度按时间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匹配失败。
本质上,有 * 两种可能性 * 取决于在部分排序期间是否忽略冲突类型:
compare("dog", "cat")
来说将是病态的。GCC rejects call to more specialized
const char
array version with string literal.