先日、boost::lexical_castの議論がTwitterでありまして
その中で「lexical_castは変換失敗時に例外を投げるが、boost::optional版も用意すべき」という意見がありました。
下位互換性を保ったまま、boost::lexical_castにboost::optional版を追加するには
lexical_cast_optionalのような別名の関数を用意する、という選択肢がありますが
C++0xで導入される関数テンプレートのデフォルトテンプレート引数を使用すれば
これをオーバーロードで解決することができます。
以下は、関数テンプレートのデフォルトテンプレート引数に対応しているGCC 4.4を使用しています。
#include <iostream> #include <sstream> #include <string> #include <typeinfo> #include <boost/optional.hpp> namespace tag { struct exception; struct optional; } // namespace tag struct bad_lexical_cast {}; template <class To, class From> inline bool lexical_convert(To& result, From x) { std::stringstream ss; return ss << x && ss >> result; } template <class To, class From, class ErrorTag> struct lexical_cast_t { typedef To result_type; static To call(From x) { To result; if (!lexical_convert(result, x)) throw bad_lexical_cast(); return result; } }; template <class To, class From> struct lexical_cast_t<To, From, tag::optional> { typedef boost::optional<To> result_type; static boost::optional<To> call(From x) { boost::optional<To> result = To(); if (!lexical_convert(*result, x)) return boost::none; return result; } }; template <class To, class ErrorTag = tag::exception, class From> inline typename lexical_cast_t<To, From, ErrorTag>::result_type lexical_cast(From x) { return lexical_cast_t<To, From, ErrorTag>::call(x); } int main() { try { int n1 = lexical_cast<int, tag::exception>("123"); std::cout << n1 << std::endl; int n2 = lexical_cast<int>("xyz"); static_cast<void>(n2); // no use } catch (bad_lexical_cast&) { std::cout << "bad_lexical_cast" << std::endl; } boost::optional<int> n1 = lexical_cast<int, tag::optional>("456"); std::cout << n1.get() << std::endl; if (boost::optional<int> n2 = lexical_cast<int, tag::optional>("xyz")) { std::cout << n2.get() << std::endl; } else { std::cout << "lexical_cast error" << std::endl; } }
123 bad_lexical_cast 456 lexical_cast error