使用引用类型重载时对函数的调用不明确

问题描述 投票:0回答:2

我用两种不同的参数类型重载函数 f 。

在source.h中,我声明了两个函数。

void f(int&);
void f(int);

我有两个函数,一个接受引用类型,另一个接受值(分别是按引用传递和按值传递)。

在source.cpp中我定义了它们

void f(int& a){
    a + 1;
}

void f(int a){
    a + 1;
}

然后,在主函数中

int main() {
    int a = 1;
    int& b = a;
    f(b);
}

编译器 (clang-tidy) 检测到一个问题:对 f 的调用不明确。 为什么会发生这种情况?

int&
int
是两种不同的类型吗?如果是这样,为什么编译器没有检测到定义函数的source.cpp中的问题?

c++ overloading pass-by-reference pass-by-value ambiguous
2个回答
1
投票

对你的问题的评论有很好的解释。

但是出于一些明显的原因,如果您想编译代码,请进行第二个整数声明

const
(我的意思是
const int& b = a;
)。

#include "iostream"

void f(int& a) {
    a + 1;
}

void f(int a) {
    a + 1;
}

int main()
{
    int a = 1;
    const int& b = a;
    f(b); //But this will call f(int) only. Refer comments to your question.
}

1
投票

为什么会发生这种情况? int& 和 int 是两种不同的类型吗?

认为将变量名传递给函数意味着参数与变量具有精确相同的类型,这是错误的。

C++ 中的引用并不是完全不同的类型。特别是表达式,例如命名用作函数参数的变量的 id 表达式,never 具有引用类型。如果将引用变量命名为 id 表达式,则 id 表达式具有变量引用类型的引用类型

C++ 中引用的要点在于,它们在表达式中的行为完全就像您已命名引用直接绑定到的对象一样。所以无论你写

f(a)
还是
f(b)
,结果都应该完全一样。

因此,

b
的类型是引用限定的这一事实对于重载解析来说并不重要。重载解析只知道参数的类型为
int
并且它是左值表达式(即引用对象而不是抽象值的表达式)。

这两种函数重载都是可行的,并且没有任何明确的偏好,因此规则规定,引用和非引用参数之间的此类重载尝试,其中转换序列的排名相同(在这两种情况下,身份转换序列)都是不明确的。

如果是这样,为什么编译器没有检测到定义函数的source.cpp中的问题?

编译器会检测到

main.cpp
中的问题,因为该问题会强制编译失败。如果您的编译器没有抱怨,那么这就是编译器中的错误。

source.cpp
中没有问题,因为仅定义两个函数重载绝对没有问题。唯一的问题是用
int
左值作为参数来调用它们是不明确的。如果您尝试传递其他内容,例如a
long
,那么两个重载中只有一个是可行的并且可以被选择。拥有两个重载通常没有什么问题。

© www.soinside.com 2019 - 2024. All rights reserved.