AnT*_*AnT 10 c++ arrays templates overload-resolution
由于重载解析不明确,此代码示例无法编译
void g(char (&t)[4]) {}
void g(char *t) {}
int main()
{
char a[] = "123";
g(a);
}
Run Code Online (Sandbox Code Playgroud)
仔细阅读重载解析规则可以清楚为什么失败。这里没有问题。
如果我们正式将其改造为模板版本
template <typename T> void g(T (&t)[4]) {}
template <typename T> void g(T *t) {}
int main()
{
char a[] = "123";
g(a);
}
Run Code Online (Sandbox Code Playgroud)
它将继续“按预期”运行,并因同样性质的模糊性而失败。到目前为止,一切都很好。
然而,下面的版本编译没有任何问题并选择了第二个重载
template <typename T> void g(T &t) {}
template <typename T> void g(T *t) {}
int main()
{
char a[] = "123";
g(a);
}
Run Code Online (Sandbox Code Playgroud)
如果我们注释掉第二个重载,第一个重载将成功地与推导为T一起使用char [4],即模板参数推导按第一个版本的预期工作,有效地使其相当于void g(char (&t)[4])。因此,乍一看,第三个示例的行为应该与前两个示例相同。
然而,它可以编译。在第三种情况下,什么[模板]重载解析规则可以挽救局面并指示编译器选择第二个重载?为什么它更喜欢数组到指针的转换而不是直接引用绑定?
PS 我发现很多关于 SO 的问题都针对非常相似的问题,但它们似乎在一些重要的细微差别上有所不同。
在函数模板的部分排序期间,第二个重载比第一个重载更专业。
根据[temp.deduct.partial]/5,T &t在为部分排序执行模板参数推导期间,第一个重载的引用将被忽略。仅当两个参数都是引用类型时,以下段落才根据引用/值类别进行区分。
然后T,第一个重载总是可以根据A*第二个重载的参数发明的类型进行推导,但T*第二个重载的不能根据A第一个重载的参数发明的类型进行推导。
因此,第二个重载更加专门并被选择。
对于T (&t)[4]论证,两个方向的演绎都会失败,因为T[4]反对的演绎将会失败,反对A*的演绎也会失败。数组类型的数组到指针衰减是为函数调用的模板参数推导指定的,但不是为部分排序的模板参数推导指定。另请参阅有效的CWG 问题 402。T*A[4]
因此,在这种情况下,两个模板都不会更加专业,并且部分排序决胜局不适用。
数组到指针的转换不相关。它不被认为比恒等转换序列更差(参见[over.ics.rank]/3.2.1不包括数组到指针转换的左值转换)。
| 归档时间: |
|
| 查看次数: |
753 次 |
| 最近记录: |