单参函数前面加上explicit描述
前两天,写到一个unsigned int 打印到ostringstream,编译居然报错,出错的地方如下:
std::ostringstream & operator<< (std::ostringstream &ostr,const TEST_PET_ID &info)
{
//test_uin_是一个unsigned int
//下面这一行报错,
ostr<< info.test_uin_;
……
}
由于我使用了STLport,错误信息被输出成很长,问了问周围的同事,发现其他几个人也遇到了,有几个人用在前面增加打印一个” ”规避了这个编译错误。不想偷懒规避,仔细看了看错误信息,错误ID是C2666,如下:
h:\courage\construct.test\construct.test\construct.test.cpp(19) : error C2666: 'operator <<' : 18 overloads have similar conversions
1> h:\havefun\stlport\stlport.5.2.1\stlport\stl\_ostream.h(130): could be 'stlp_std::basic_ostream<_CharT,_Traits>
&stlp_std::basic_ostream<_CharT,_Traits>::operator <<(unsigned int)'
.. .. .. ..
1> h:\courage\construct.test\construct.test\construct.test.cpp(17): or 'stlp_std::ostringstream &operator <<(stlp_std::ostringstream &,const TEST_QQ_UIN &)'
1> while trying to match the argument list '(stlp_std::ostringstream, const unsigned int)'
MSDN错误信息和检查错误提示,发现是编译器无法抉择是使用,unsigned int 的输出到ostringstream的函数还是使用TEST_QQ_UIN结构的输出到ostringstream的函数。看了一下TEST_QQ_UIN的结构,发现了问题所在。
把错误的代码提炼出来,让大家容易看到问题所在:
#include <stdio.h>
#include <sstream>
struct TEST_QQ_UIN
{
//在构造函数前面增加explicit,就正确了。
TEST_QQ_UIN(unsigned int qq_uin):
qq_uin_(qq_uin)
{
}
~TEST_QQ_UIN()
{
}
unsigned int qq_uin_;
};
std::ostringstream & operator<< (std::ostringstream &ostr,const TEST_QQ_UIN &info)
{
ostr<<info.qq_uin_;
return ostr;
}
struct TEST_PET_ID
{
TEST_PET_ID():
test_uin_(0),
pet_type_(0)
{
}
~TEST_PET_ID()
{
}
unsigned int test_uin_;
unsigned short pet_type_;
};
std::ostringstream & operator<< (std::ostringstream &ostr,const TEST_PET_ID &info)
{
ostr<< info.test_uin_; //出错的代码,错误C2666
ostr<< info.pet_type_;
return ostr;
}
//测试
int main(int /*argc*/ ,char * /*argv*/ [])
{
return 0;
}
TEST_QQ_UIN 有一个单参数的构造函数,而且前面没有加explicit,所以编译器在处理unsigned int作为参数的时候,可以转换为TEST_QQ_UIN,编译器也无法知道是使用哪个ostringstream输出函数,这样导致了编译器报告错误。BTW:其他兄弟利用” ”避免错误,应该是MSVC++的一个bug。
所以单参的构造函数,没有特别情况下,在构造函数前面都加入explicit,避免这种默认的转换。这个Effective C++讲过了,这儿有炒剩饭的嫌疑。糟糕的是,很多事情只有经历了,才知道痛苦。