我试图理解重载选择规则是如何导致以下(不直观的)行为的。当我有以下职能时:
#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 = int和void 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)。
发布于 2018-09-20 18:12:18
我想这是GCC的一个错误:
超载情况如下:
write(const int&)write(T) [T=int] -> write(int)write(T&&,U&&...) [T=int&,U=[]] -> write(int&)重载0比重载1更匹配,因为重载0不是模板函数的专门化。
重载1比重载2更匹配,因为重载1是比重载2更专业的函数模板。
重载2比重载0更匹配,因为重载2 int&的参数类型的cv限定符是重载0:const int&的子集。
因此,正如Clang报告的那样,这一呼吁是模棱两可的。
为了简化,最好的可行函数是在这里按4个步骤计算,当比较两个函数时:
https://stackoverflow.com/questions/52428882
复制相似问题