문자열을 숫자로, 또는 그 반대로 변환하는 함수는
기존 C 라이브러리에 존재합니다.
우선 문자열을 숫자로 변환하는 함수는 다음과 같은 ANSI C 라이브러리에 있습니다.
char*를 int로 변환: atoi
char*를 long으로 변환: atol, strtol
char*를 double로 변환: atof, strtod
숫자를 문자열로 변환하는 함수는 ANSI C 라이브러리에는 없지만,
BC++에는 있습니다(VC++에도 있습니다.).
int를 char*로 변환: itoa
long을 char*로 변환: ltoa
double을 char*로 변환: ecvt, fcvt, gcvt
그 외에 번거롭지만, 다양한 서식을 지정할 수 있는 방법인,
sprintf와 sscanf를 사용하는 방법이 있지요.
C++에서는 stringstream 객체를 사용하는 방법이 있죠.
이러한 방법들은, 각 함수마다 사용법과 특성(확장성과 안정성 등)이 제각각이라,
일일히 레퍼런스(도움말)를 뒤져가며 사용해야 합니다.
C++에서는 문자열을 char* 보다는 string 객체를 쓰는 것을 권장하기 때문에
위의 C 함수를 쓰는 코드는 별로 깔끔해 보이지 않지요.
게다가, 기본 타입인 int, long, double 만을 변환할 수 있습니다.
std::complex나 boost::rational과 같은 것들은 물론 변환할 수 없죠.
어떠한 변환이든 항상 동일한 방법으로 할 수 있다면 편리하겠죠?
이를 위해 Boost 라이브러리는 lexical_cast 연산자(정확히는 템플릿 함수)를 제공합니다.
stringstream 객체를 사용하는 방법을 약간 개선한 겁니다.
stringstream 객체를 사용해서 변환하려면 별도의 로컬 변수를 선언하는 등,
귀찮은 점이 많은데요, 이런 것들을 간단하게 쓸 수 있는 템플릿 함수를 제공하는 거죠.
물론 lexical_cast의 구현은 매우 간단합니다.
컴파일러 환경 설정을 위한 잡다한 프리프로세서 문장을 모두 제거하면
다음 코드와 같습니다.
(부스트 라이브러리 전체를 설치하시기 싫으신 분은 다음 코드만 있으면 됩니다.)
class bad_lexical_cast : public std::bad_cast
{
public:
// constructors, destructors, and assignment operator defaulted
// function inlined for brevity and consistency with rest of library
virtual const char * what() const throw()
{
return "bad lexical cast: "
"source type value could not be interpreted as target";
}
};
template<typename Target, typename Source>
Target lexical_cast(Source arg)
{
std::stringstream interpreter;
Target result;
if(!(interpreter << arg) || !(interpreter >> result) ||
!(interpreter >> std::ws).eof())
throw bad_lexical_cast();
return result;
}
캐스팅에 실패하면 bad_lexical_cast(bad_cast 예외 클래스를 계승한) 예외를 throw하지요.
(dynamic_cast에서 캐스팅 실패시 bad_cast 예외를 throw하는 것은 알고 계시겠죠?)
사용법은 상당히 간단합니다. 간단한 예제 코드를 올립니다.
int main(int argc, char * argv[])
{
using boost::lexical_cast;
using boost::bad_lexical_cast;
std::vector<short> args;
while(*++argv)
{
try
{
args.push_back(lexical_cast<short>(*argv));
}
catch(bad_lexical_cast &)
{
args.push_back(0);
}
}
...
}
예외 처리 부분에 주목해보세요.
사실상 if ... else 대신 try ... catch 가 대신 사용되었다고 할 수 있지요.
|