添加重载更改选择的重载

Adding overload changes which overload is selected

本文关键字:重载 选择 添加      更新时间:2023-10-16

我试图了解重载选择规则如何导致以下(不直观(行为。当我有以下功能时:

#include <iostream>
// Overload 1
template<class T>
void write(T data)
{
std::cout << "Called write(T data)" << std::endl;
}
// Overload 2
template<class T, class ...U>
void write(T&& obj, U&&... objs)
{
std::cout << "Called write(T&& obj, U&&... objs)" << std::endl;
}
int main(int, char**)
{
int j = 0;
write(j);
return 0;
}

选择void write(T data)重载(重载 1(。我认为这对我来说是有道理的:超载选择的候选人是void write<T>(T)T = intvoid write<T,U>(T&)T = int, U = <>.write(T)write(T&)都同样专业,但重载 2 有一个空的参数包,因此选择了重载 1。但是,如果我添加第三个重载:

#include <iostream>
// Overload 0
void write(const int& data)
{
std::cout << "Called write(const int& data)" << std::endl;
}
// Overload 1
template<class T>
void write(T data)
{
std::cout << "Called write(T data)" << std::endl;
}
// Overload 2
template<class T, class ...U>
void write(T&& obj, U&&... objs)
{
std::cout << "Called write(T&& obj, U&&... objs)" << std::endl;
}
int main(int, char**)
{
int j = 0;
write(j);
return 0;
}

然后突然之间void write(T&& obj, U&&... objs)(过载 2(就是所谓的。为什么添加未选择的重载会更改实际选择的重载?

如果唯一的候选人是void write<T,U>(T&)T = int, U = <>并且void write(const int&)我理解为什么void write<T,U>(T&)会被选中,所以也许添加额外的重载会阻止void write(T data)参与重载选择?如果是这样,为什么?

由于这似乎是编译器特定的行为,因此在 gcc 7.3.0 上观察到了这一点。

一些更有趣的行为: 如果对函数进行重新排序,以便将新的重载放置在原始两个重载之间(即重载 1,然后重载 0,然后重载 2(,则 gcc 用call of overloaded ‘write(int&)’ is ambiguous拒绝它。如果对函数进行重新排序,以便新的重载是最后一个(即重载 1,然后重载 2,然后重载 0(,则选择write(const int& data)

我认为这是一个 GCC 错误:

重载包括:

  • 过载 0:write(const int&)
  • 过载 1:write(T) [T=int] -> write(int)
  • 过载 2:write(T&&,U&&...) [T=int&,U=[]] -> write(int&)

重载 0比重载 1 匹配得更好,因为重载 0 不是模板函数专用化。

重载 1 比重载 2 更匹配,因为重载 1 是比重载 2 更专业的函数模板。

重载 2比重载 0 匹配得更好,因为重载 2int&参数类型的 cv 限定符是重载 0:const int&之一的子集。

因此,正如Clang报道的那样,该电话是模棱两可的。


为了简化起见,在比较两个函数时,这里分 4 个步骤评估最佳可行函数:

  1. 检查哪个是最佳转换序列(此处的所有转换都是身份转换(,然后如果转换排名相同:
  2. 检查两个引用绑定
  3. 之间一个是否比另一个好,那么如果一个不是引用绑定或两个绑定不可微分,
  4. 检查其中一个函数是否是模板专用化,
  5. 另一个不是,则检查这两个函数是否是模板专用化
  6. 检查其中一个专业是否比另一个专业更专业。