前段时间发现自己的String库中有个bug:
String& operator+=(int);
String& operator+=(unsigned);
// 所有的整型、浮点型都有一个operator+=的重载
template <typename T>
String& operator+=(const T& t)
{
std::stringstream ss;
ss << t;
this->operator+=(ss.str());
return *this;
}
对所有的整型、浮点型、std::string,String::operator+=都有一个高效的实现,但唯独忽略了对enum的特殊处理,即使enum能通过integral promotion自动转换为int。
这样,在用“+=”连接字符串和enum类型的时候,String类会调用template版本的operator+=,具体操作包括一个局部std::stringstream变量的创建和析构,一次(低效的)stringstream::operator<<的调用,一个临时std::string变量的创建和析构(由ss.str()引起)。
这样的操作序列,性能之低可以想象。我的代码中对enum和String类有大量使用,导致程序的性能下降了30%。
问题的解决非常容易,TR1中(以及C++ 11中)有个叫做is_enum的traits,根据这个traits,很容易就能把来自enum的String::operator+=的调用定向到enum对应的int类型的String::operator+=的调用。
但是这样就引入了一个新问题,如果某个enum EnumA自己定义了operator<<:
std::ostream& operator<<(std::ostream&, EnumA);
那么按照老代码,它能够经由template版本的String::operator+=调用到这个operator<<,而打了patch后的String,在调用+=的时候却会出现不一致的行为:
enum