提问人:DannyBoy 提问时间:11/4/2022 最后编辑:Usitha IndeewaraDannyBoy 更新时间:11/5/2022 访问量:432
具有相同名称的多个函数,但其参数要么是常量,要么是按值或按引用接收的
Multiple functions with the same name but their parameters are either constant or received by value or by reference
问:
标题有点长,但最好用一个例子来解释:
假设我们在 C++ 中有以下函数:
void SomeFunction(int num) { //1
}
void SomeFunction(int& num) { //2
}
void SomeFunction(const int& num) { //3
}
void SomeFunction(const int num) { //4
}
所有这些都以相同的方式调用:
SomeFunction(5);
或
int x = 5;
SomeFunction(x);
当我尝试编译代码时,它正确地说more than one instance of overloaded function "SomeFunction" matches the argument
我的问题是:有没有办法告诉编译器我要调用哪个函数?
我问我的讲师是否可能,她尝试了一些方法
SomeFunction< /*some text which I don't remember*/ >(x);
但它没有用,她让我找出来并告诉她。
我也遇到过这篇文章:如果其中一个有引用,如何定义两个具有相同名称和参数的函数?而且似乎 1 和 2 不能一起写,但是 3 和 4 呢?其中任何一个都可以具体称呼吗?
答:
你可以破解它,我是认真的 - 这不是解决你问题的好办法,通过静态转换你的函数显式:
static_cast<void(*)(int)>(SomeFunction)(i);
static_cast<void(*)(int&)>(SomeFunction)(i);
static_cast<void(*)(const int&)>(SomeFunction)(i);
演示它将适用于前 3 次重载。第 4 个等同于第 1 个:引用标准 [over.load]:
仅在存在或不存在常量和/或 volatile 时有所不同的参数声明是 等效。也就是说,在以下情况下,将忽略每个参数类型的 const 和 volatile 类型说明符 确定正在声明、定义或调用哪个函数
有一个例子:
int f (int);
int f (const int); // redeclaration of f(int)
另请注意,不能使用右值(临时)调用第二个重载。
评论
int var = static_cast<int(*)(int&)>(SomeFunction)(i);
i
1 和 4 具有相同的签名,因此您需要删除其中一个签名。
不能直接调用其他函数,但可以添加一个模板函数,该函数允许您指定所需的参数类型:
template<class Arg>
void Call(void f(Arg), Arg arg)
{
f(arg);
}
// Driver Program to test above functions
int main()
{
int i;
Call<int>(SomeFunction, 1);
Call<int&>(SomeFunction, i);
Call<const int&>(SomeFunction, 1);
}
或者,您可以使用函数指针来选择签名。
int i;
static_cast<void(*)(int)>(&SomeFunction)(1);
static_cast<void(*)(int&)>(&SomeFunction)(i);
static_cast<void(*)(const int&)>(&SomeFunction)(1);
不过,最好避免这种情况,只为引用或签名定义重载。void SomeFunction(int)
注意:
SomeFunction<some text which I don't remember>(x);
仅适用于模板函数,不是模板函数,因此此处不是一个选项。SomeFunction
评论
template<class Arg, class returnType> returnType Call(returnType f(Arg), Arg arg) {return f(arg);}
int var = Call<int, int>(SomeFunction, 1);
int var=static_cast<int(*)(int)>(SomeFunction)(1);
我看到它以您的讲师尝试的方式工作的唯一方法是,如果是一个模板,而这四个重载是专业化。SomeFunction
template<typename T>
void SomeFunction(T num);
template<>
void SomeFunction<int>(int num) {}
template<>
void SomeFunction<int&>(int& num) {}
template<>
void SomeFunction<const int&>(const int& num) {}
template<>
void SomeFunction<const int>(const int num) {}
然后你可以按如下方式调用它。
SomeFunction<int>(x);
SomeFunction<int&>(x);
SomeFunction<const int&>(x);
SomeFunction<const int>(x);
然而,在这种情况下,这是非常愚蠢的。原始重载有很多问题。
在第 4 个中,从调用者的角度来看,the 是完全没用的,因为你可以用同样的方式调用它,你可以调用第一个,而且无论如何,参数都是一个副本。唯一使得它使参数在函数内是常量。此外,第 1 和第 4 重载不能同时定义:实际上在原型中被忽略了,它导致了重新定义。const
const
const
第三个重载也是无用的,因为参数比参数没有好处。事实上,编译器可能会对其进行优化。唯一的区别在于我在最后描述的场景。当然,如果参数类型更复杂(不仅仅是或其他一些基本类型),它通常是有道理的。const int&
int
int
第二个重载是唯一可以修改作为参数传递的变量的重载。但是,如果还存在第一个(或第四个,因为它实际上是一样的)重载,则不能直接调用第二个,因为调用会不明确。您仍然可以使用右值(基本上是文字或类似 )调用 1ststd::move(x)
如果只有第 2 个和第 3 个重载,则没有歧义,您可以调用具有非常量左值的第 2 个重载和具有常量左值或右值的第 3 个重载。
评论
int
评论
SomeFunction(int num)
SomeFunction(const int num)
SomeFunction(const int& num)
SomeFunction(int num)
SomeFunction(const int num)