众所周知,C++函数重载时返回值是不参与重载决议的, 也就是说:
int lex_cast(const char*);
double lex_cast(const char*);
这样两个函数在同一个编译单元同一个 namespace 中时, 会编译报错.
怎么办呢?
一个小技巧:
#include <iostream>
#include <string>
#include <boost/lexical_cast.hpp>
class my_cast {
const char* s;
public:
template<class Target>
operator Target() const {
return boost::lexical_cast<Target>(s);
}
my_cast(const char* s) : s(s) {}
};
int main() {
using namespace std;
long long ll = my_cast("12345678910111213");
int ii = my_cast("-123");
string ss = my_cast("abcde");
double dd = my_cast(('3' + string(".2222")).c_str());
cout << ll << endl;
cout << ii << endl;
cout << ss << endl;
cout << dd << endl;
return 0;
}
小得几乎不值一提. 但是, 这段代码中, 可能有些仔细的人会提出疑问:
('3' + string(".2222")).c_str()
这里返回的 const char* 是属于临时变量的, 而 my_cast 竟然把这个临时变量保存到它的成员, 这里能成功并无错应该只是因为被释放的 c_str() 那块内存恰好未被重新分配, 太危险了!
其实, 这没任何问题, C++ 标准规定: 临时变量的生存期是包含它的那个表达式(整个), 而非任何一个真子表达式. 仔细体味这句话吧!
上面只是在 my_cast 非模板的情况, 如果 my_cast 包含模板参数, 并且 my_cast 成员也必须是模板, 怎么办?
template<class Source>
class my_cast_imp {
Source s;
public:
template<class Target>
operator Target() const {
return boost::lexical_cast<Target>(s);
}
my_cast_imp(const Source& s) : s(s) {}
};
template<class Source>
my_cast_imp<Source> my_cast2(const Source& s) {
return my_cast_imp<Source>(s);
}
只需定义一个辅助模板类, 再加一个模板函数去实例化模板类.
核心思想只有一个: 使用 operator class conversion, 下面是一个比较实用的 cast, 没有用 boost::lexical_cast, 没有编译龟速的问题. (boost 过度使用 template 了)
#include <stdlib.h>
#include <string>
class goldcast_imp {
const char* s;
int base;
public:
goldcast_imp(const char* s, int base)
: s(s), base(base)
{}
operator int () const { return (int) strtol (s, NULL, base); }
operator unsigned() const { return (unsigned)strtoul(s, NULL, base); }
operator signed long () const { return strtol (s, NULL, base); }
operator signed long long() const { return strtoll (s, NULL, base); }
operator unsigned long () const { return strtoul (s, NULL, base); }
operator unsigned long long() const { return strtoull(s, NULL, base); }
operator float() const { return strtof(s, NULL); }
operator double() const { return strtod(s, NULL); }
operator long double() const { return strtold(s, NULL); }
operator std::string() const { return std::string(s); }
};
goldcast_imp goldcast(const std::string& s, int base = 10) {
return goldcast_imp(s.c_str(), base);
}
goldcast_imp goldcast(const char* s, int base = 10) {
return goldcast_imp(s, base);
}