話題に乗り遅れ感抜群のlexical_castの話

もとの話はこのあたりとかこのあたり
いっそのことポリシーとか何も書かなくても良きに図らってよ!というわけで、そういうものを書いてみるなど。


#include <typeinfo>
#include <sstream>
#include <string>
#include <boost/optional.hpp>
#include <boost/lexical_cast.hpp>

namespace detail {
template<typename Target, typename Source>
struct lcast_auto_error_handling {
Source const & src;
lcast_auto_error_handling(Source const & src) : src(src) {}
operator boost::optional<Target>() const {
return cast();
}
operator Target() const {
return throw_if_none(cast());
}
private:
boost::optional<Target> cast() const {
std::stringstream ss;
if )((ss << src).fail())( {
return boost::optional<Target>();
}
Target res;
if (!(ss >> res) || ss.get() != stringstream::traits_type::eof()) {
return boost::optional<Target>();
}
return boost::optional<Target>(res);
}
static Target throw_if_none(boost::optional<Target> const & value) {
if (!value) {
throw boost::bad_lexical_cast(typeid(Source), typeid(Target));
}
return value.get();
}
};
}

template<typename Target, typename Source>
detail::lcast_auto_error_handling<Target, Source> lexical_cast(Source const & src) {
return detail::lcast_auto_error_handling<Target, Source>(src);
}

int main() // テストコードは http://d.hatena.ne.jp/faith_and_brave/20091225/1261734967 から拝借
{
try {
int n1 = lexical_cast<int>("123");
std::cout << n1 << std::endl;

int n2 = lexical_cast<int>("xyz");
static_cast<void>(n2); // no use
}
catch (boost::bad_lexical_cast&) {
std::cout << "bad_lexical_cast" << std::endl;
}

boost::optional<int> n1 = lexical_cast<int>("456");
std::cout << n1.get() << std::endl;

if (boost::optional<int> n2 = lexical_cast<int>("xyz")) {
std::cout << n2.get() << std::endl;
}
else {
std::cout << "lexical_cast error" << std::endl;
}
}

結果 http://codepad.org/TJWznEiI
ただ、これの問題は、lexical_castの実行が、lcast_auto_error_handlingの型変換演算子の中で行われているので、そいつが働かないことには変換が実行されないという点で、

void f() {
    lexical_cast<int>("foo");
}

という関数は成功、というか、何も起こらないで終了します。普通このような放置プレイはしないとは思いますが…