提问人:user22879756 提问时间:11/8/2023 最后编辑:user12002570user22879756 更新时间:11/9/2023 访问量:195
整数参数调用 float 重载和 float 参数调用整数重载?[复制]
Integer parameter calls float overload and float parameter calls integer overload? [duplicate]
问:
今天我遇到了大致以下代码:
#include <iostream>
void f(float&& f) { std::cout << f << "f "; }
void f(int&& i) { std::cout << i << "i "; }
int main()
{
int iv = 2; float fv = 1.0f;
f(2); f(1.0f);
f(iv); f(fv);
}
按预期打印前两个 f 调用。2i 1f
现在对于第二行,我本来希望它要么根本不编译,因为 iv 和 fv 不是临时的(因此不能绑定到 r 值引用),要么它创建变量的副本以传递给函数,从而第二次打印。2i 1f
然而,不知何故,它打印了 ,这几乎是我所期望的最后一件事。2f 1i
如果将代码复制到 cppinsights 中,它会将调用转换为
f(static_cast<float>(iv));
f(static_cast<int>(fv));
所以它似乎非常有意地将整数转换为浮点数,将浮点数转换为整数,但我不知道它为什么要这样做,也不知道如何谷歌搜索。为什么会这样?导致此结果的规则是什么?
答:
为避免将隐式转换视为隐式转换,请像这样重写代码。使用 C++17 语法(因为你在 godbolt 链接中使用了它) 至少错误的代码现在不会编译。
通过显式约束,类型必须完全匹配,并且不考虑隐式转换。(C++ 语法会更好一些)
演示 : https://godbolt.org/z/MexsGT55T
#include <iostream>
#include <type_traits>
template<typename type_t>
auto f(type_t&& f) -> std::enable_if_t<std::is_same_v<type_t,float>,void>
{
std::cout << f << "f ";
}
template<typename type_t>
auto f(type_t&& f) -> std::enable_if_t<std::is_same_v<type_t,int>,void>
{
std::cout << f << "f ";
}
int main()
{
int iv = 2;
float fv = 1.0f;
f(2); f(1.0f);
f(iv); f(fv); // <== will no longer compile now
}
评论
same_as
is_same
auto f(std::same_as<int> auto && f)
程序的行为可以从引用初始化中理解。
[示例6:
double d2 = 1.0; double&& rrd2 = d2; // error: initializer is lvalue of related type int i3 = 2; double&& rrd3 = i3; // rrd3 refers to temporary with value 2.0
-end example]
案例 1
在这里,我们讨论为什么电话不可行。void f(int&& i)
f(iv)
左值不能绑定到调用中的右值引用参数,因此重载不可行。基本上,不允许,因为是相关类型的左值。iv
i
void f(int&& i)
f(iv)
f(int&&)
int&& i = iv;
iv
案例 2
在这里,我们讨论为什么电话是可行的。void f(float&& i)
f(iv)
对于调用,重载是可行的,因为在这里,首先将初始值设定项表达式隐式转换为目标 type() 的 prvalue,然后可以发生临时具体化,以便参数可以绑定到该具体化的临时(即 xvalue)。f(iv)
void f(float&& f)
iv
float
f
2.0f
同样,对于调用,重载是不可行的,因为是相关类型的左值。对于调用,可以使用重载,因为首先将初始值设定项隐式转换为 prvalue,然后发生临时具体化,以便可以绑定到具体化的临时(类型)。f(fv)
void f(float&& i)
fv
f(fv)
void f(int&& i)
i
1
int
评论
int iv = 2; int&& i = iv; /*won't work*/ float&& f = iv; //this will work
若要避免隐式转换,请提供一个删除函数模板,如果非模板化重载不完全适合,则选择该模板。也就是说,只需添加以下重载:
template<typename T>
void f(T&&) = delete;
评论
f(iv);
不能绑定到 ,但它可以通过临时绑定。反之亦然。f(int&&)
f(float&&)
f(fv)