【发布时间】:2018-07-02 12:33:39
【问题描述】:
为什么接下来的两个模板声明是模棱两可的(所以没有一个比另一个更专业)?我知道这个问题已经在 Stack Overflow 上提出过很多次了,但通常人们会回答如何解决歧义,而不是为什么会发生这种情况。
我。
template <class T> void func(char* buf, T size) {}
二。
template <std::size_t N> void func(char (&buf)[N], std::size_t size) {}
尝试通过 C++14 标准的步骤来解决部分函数模板排序 (14.5.6.2):
为每个类型、非类型或模板模板参数(包括 模板参数包(14.5.3))分别合成一个唯一的类型、值或类模板 并将其替换为模板函数类型中该参数的每次出现。
转换后的函数 I 模板的函数类型是:void func(char*, U1),其中U1 是一些独特的合成类型。
转换后的函数II模板的函数类型是:void func(char (&buf)[N1], std::size_t),其中N1是一些唯一的合成值。
使用转换后的函数模板的函数类型,对另一个模板进行类型推导 如 14.8.2.4 中所述。
所以让我们尝试在一侧(使用第一个模板作为参数,第二个作为参数模板)和另一侧执行类型推导。
案例 1。
参数模板:template <std::size_t N> void func(char (&buf)[N], std::size_t size)。
转换后的参数模板:void func(char*, U1)。
试图推断模板参数。 “char (&buf)[N]”不能从“char*”类型推导出来。 U1 也不匹配 std::size_t 类型。失败。
案例 2。
参数模板:template <class T> void func(char* buf, T size)。
转换后的参数模板:void func(char (&buf)[N1], std::size_t)。
试图推断模板参数。参数模板的第一个参数根本不是类型,它与char[] 兼容。 T 应该推导出为std::size_t。
所以模板二应该更专业,应该在下面的代码中选择:
char buf[16];
func(buf, static_cast<std::size_t>(16));
为什么 GCC 5.3 和 Clang 4.0 不是这样?
【问题讨论】:
-
很抱歉,这个问题写得有点混乱。我不明白 case 1 和 case 2 对应的是什么,也不明白你在每个例子中是如何称呼它的,也不明白为什么 U1 不匹配
std::size_t。更一般地说,我会添加数组到指针的转换非常激进,并且在过去弄清楚这种转换是否真的影响排序是很棘手的。不过,SO 上已经有多个此类问题。 -
我不确定这是关于偏序的,但可能是一个函数在第一个参数上更匹配,另一个在第二个参数上匹配。
-
1.函数调用的偏序不使用函数类型;它单独使用参数类型。 2. 已知该领域的规范存在问题。对于这个,尚不清楚在偏序期间是否或在什么情况下检查原始和推导的 A 的身份。如果它们被如此检查,那么
P=char *和A=char [N1]将无法扣除。 (也就是说,如果我们忽略 CWG 1391 对 [temp.deduct.partial]p4 的可疑添加,这会导致其自身的问题。) -
@T.C.那么如果考虑到 CWG 1391,这个 A/P 扣除就不会继续,模板 II 会被认为更专业?
-
我想知道您期望的答案是什么。如果编译器不符合 C++ 标准,那么答案就是这样。你可以用“为什么 Visual Studio 2006 不符合 C++03”来问同样的原因。顺便说一句,这并不是编译器不兼容的唯一情况。我向 Clang 和 GCC 提交的 100 份律师错误报告中的一些在我提交报告数年后仍然开放。 bugs.llvm.org/…
标签: c++ c++11 templates standards-compliance partial-ordering