C++函数重载的一点问题
问题
#include <iostream>
#include <vector>
enum A { Value = 1 };
void a(std::vector<int>) {
std::cout << "a1" << std::endl;
}
void a(A e) {
std::cout << "a2:" << e << std::endl;
}
//void a(int t) {
// std::cout << "a3:" << t << std::endl;
//}
int main() {
a({});
// a({1});
// a({Value});
// a({1,2});
return 0;
}
这段代码,想想会输出哪个?
我会选择输出 a1
,我想应该有很多人跟我的选择是一致的。
因为按照C的习惯,enum A
实际上可能是一个整形,而{}
最可能的是个数组,
最符合直觉的结果肯定是输出a1
但实际上,无论用g++还是clang++,输出的结果都是 a2:0
分析
接着上面的代码,如果在main中写下面的代码:
A c = {};
std::cout << "A:" << c << std::endl;
它会编译通过,并始终输出A:0
,这证明enum是可以用{}
初始化的
那其他类型呢?
是的,几乎所有的基础类型都可以
显然,编译器认为,初始化一个enum A
,比初始化一个std::vector<int>
要简单,
在函数重载中,void a(A e)
是一个更直接的匹配
同样如果注释void a(A e)
函数,将void a(int t)
解注释,应该知道会输出什么结果了。
思考1
这让我想起了int i(1);
这种直接初始化方式。那这与上面的列表初始化有什么不同?
int i = 1.1; // 正确
int i = {1.1}; // 编译错误
int i(1.1); // 正确
由此可见,列表初始化会显得更安全,因为它禁止窄化转换,推荐在需要严格类型检查时使用。
但是在c中,有不同的情况
int i = 1.1; // 正确
int i = {1.1}; // 正确
int i(1.1); // 错误
显然,c支持基础类型的列表初始化,并且c也允许a((int){1.1});
这种调用方式,这样语言的语法才是自洽完整的。
所以,如果一开始的问题答错了,其实跟c++关系不大,而是对c的认知还差点意思,咱还得学习。
所谓活到老,学到老
结论
在调用重载函数时,需要当心!!!不然很容易出一些难以查找的BUG