lexical cast

Standard C++ does not provide a general-purpose utility function to convert between disparate data types. The Boost library provides boost::lexical_cast, which is perhaps the canonical solution to this problem. You should use it if you can.

Alternatively, you can use the C++ stringstream class to perform the conversion, although it's a bit tricky. This is the simplest thing that could possibly work, if you don't care at all about error handling:


 * 1) include
 * 2) include
 * 3) include

const int answer = 42;

int main { std::string answer_s; { std::stringstream ss; ss << answer; ss >> answer_s; } int target; { std::stringstream ss; ss << answer_s; ss >> target; } assert(target == answer); }

You could then wrap the interesting bits into a function:


 * 1) include

template  Target lexical_cast(const Source &source) { Target target;

std::stringstream ss; ss << source; ss >> target; return target; }


 * 1) include
 * 2) include

const int answer = 42;

int main { const std::string answer_s = lexical_cast(answer); assert(lexical_cast (answer_s) == answer); }

This approach has some problems:


 * Behavior of conversion to pointer-to-char is undefined -- it may crash your program.

lexical_cast(answer) // KABOOM!


 * That's because it ends up trying to store input into some random address in memory:

char *target; // 'target' refers to some (unknown) address in memory ss >> target; // read from 'ss' and store result into memory at that (unknown) address


 * There's no way to tell if the conversion was successful:

std::cerr << lexical_cast ("3.14") << '\n';      // output: 3 std::cerr << lexical_cast ("not an int") << '\n'; // output: unknown


 * You might consider the conversion as a failure if it only read part of the data (e.g. the "3" in "3.14").

A better implementation would have the following properties:


 * It uses concept checking to generate a C++ compilation error if the target is a pointer.
 * It throws an exception if the conversion failed, including if any data (excluding whitespace) is left over.
 * Hint: (ss >> std::ws).ignore.good skips whitespace, then tries to ignore a character, then checks if it worked. If it did, then something's wrong. :)

/** Disable lexical_cast to certain types, such as pointers. */ template struct LexicallyCastableTo { }; template  struct LexicallyCastableTo;
 * 1) include
 * 2) include

/** Thrown by lexical_cast if conversion fails. */ class bad_lexical_cast : public std::bad_cast { public: explicit bad_lexical_cast(const char *msg) : m_msg(msg) { } const char *what const throw { return m_msg; } private: const char *m_msg; };

/** Similar to "target = lexical_cast(source)", but doesn't initialize nor copy an object of type Target. * @throw bad_lexical_cast Failure converting Source to string or string to Target */ template  void lexical_assign(const Source &source, Target& target) { std::stringstream ss; if (!(ss << source)) { throw bad_lexical_cast("failed to convert from source to string"); } else if (!(ss >> target) || (ss >> std::ws).ignore.good) { throw bad_lexical_cast("failed to convert from string to target"); } } /** Use std::stringstream to convert @c source to type Target. * @throw bad_lexical_cast Failure converting Source to string or string to Target */ template  Target lexical_cast(const Source &source) { LexicallyCastableTo; Target target; lexical_assign(source, target); return target; }

const int answer = 42; int main { const std::string answer_s = lexical_cast(answer); assert(lexical_cast (answer_s) == answer); std::vector bad_ints; bad_ints.push_back("not an int"); bad_ints.push_back("3.14"); bad_ints.push_back("true"); for (unsigned i = 0; i < bad_ints.size; ++i) { try { lexical_cast (bad_ints[i]); } catch(const bad_lexical_cast &) { continue; }       assert(false && "should have thrown, caught, and continued"); }   // invalid use of undefined type `struct LexicallyCastableTo' lexical_cast(answer); }
 * 1) include
 * 2) include
 * 3) include
 * 4) include
 * 1) if 0
 * 1) endif