具有相同名称的多个函数,但其参数要么是常量,要么是按值或按引用接收的

Multiple functions with the same name but their parameters are either constant or received by value or by reference

提问人:DannyBoy 提问时间:11/4/2022 最后编辑:Usitha IndeewaraDannyBoy 更新时间:11/5/2022 访问量:432

问:

标题有点长,但最好用一个例子来解释:

假设我们在 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 呢?其中任何一个都可以具体称呼吗?

C++ 常量 引用

评论

2赞 Lukas-T 11/4/2022
首先,我会质疑为什么存在这些过载。从呼叫者的角度来看,两者之间没有区别,我相信 。SomeFunction(int num)SomeFunction(const int num)SomeFunction(const int& num)
0赞 Some programmer dude 11/4/2022
重载 3 和 4 有点没用。
0赞 Fareanor 11/4/2022
您的讲师似乎不知道模板是如何工作的(也不知道什么是模板)。这不是我们可以添加任何旧方式的东西:D这些是这里的函数,而不是函数模板,因此在调用中指定模板类型显然无法编译。
2赞 Öö Tiib 11/4/2022
重载 1 和 4 并不是真正的重载,但在函数签名中忽略了违反 ODR 作为顶级常量的情况。
0赞 Caleth 11/4/2022
@churill和是相同的功能。如果有两个定义,则程序无论如何都是格式不正确的SomeFunction(int num)SomeFunction(const int num)

答:

0赞 pptaszni 11/4/2022 #1

你可以破解它,我是认真的 - 这不是解决你问题的好办法,通过静态转换你的函数显式:

    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)

另请注意,不能使用右值(临时)调用第二个重载。

评论

0赞 DannyBoy 11/5/2022
“另请注意,您不能使用右值(临时)调用第二个重载。”为什么不呢?我尝试了以下方法,它对我有用:int var = static_cast<int(*)(int&)>(SomeFunction)(i);
0赞 pptaszni 11/7/2022
因为是左值。i
1赞 fabian 11/4/2022 #2

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

评论

0赞 DannyBoy 11/5/2022
谢谢。为了解决您的问题,如果这些函数中的任何一个要返回一个值,则模板将如下所示: 调用函数: 并使用函数指针: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);
0赞 Nelfeal 11/4/2022 #3

我看到它以您的讲师尝试的方式工作的唯一方法是,如果是一个模板,而这四个重载是专业化。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 重载不能同时定义:实际上在原型中被忽略了,它导致了重新定义。constconstconst

第三个重载也是无用的,因为参数比参数没有好处。事实上,编译器可能会对其进行优化。唯一的区别在于我在最后描述的场景。当然,如果参数类型更复杂(不仅仅是或其他一些基本类型),它通常是有道理的。const int&intint

第二个重载是唯一可以修改作为参数传递的变量的重载。但是,如果还存在第一个(或第四个,因为它实际上是一样的)重载,则不能直接调用第二个,因为调用会不明确。您仍然可以使用右值(基本上是文字或类似 )调用 1ststd::move(x)

如果只有第 2 个和第 3 个重载,则没有歧义,您可以调用具有非常量左值的第 2 个重载和具有常量左值或右值的第 3 个重载。

演示

评论

0赞 DannyBoy 11/5/2022
“当然,如果参数类型更复杂(不仅仅是 int 或其他一些基本类型),它通常是有道理的。你是对的,为了简单起见,我使用了这个例子,正如你所说,这个例子无疑是“非常愚蠢的”。如果有的话,我只会将(其中一些)这些函数用于更复杂的场景。我在回复问题帖子本身的某人时也谈到了这一点。int