#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { // Some Boost.Parameter extension - this should really go to Boost.Parameter in the end namespace parameter { // The metafunction, given the type of the arguments pack and the keyword tag, returns the corresponding parameter type template< typename ArgsT, typename KeywordTagT > struct parameter_type { typedef void type; }; template< typename ArgT, typename KeywordTagT > struct parameter_type< aux::tagged_argument< KeywordTagT, ArgT >, KeywordTagT > { typedef typename aux::tagged_argument< KeywordTagT, ArgT >::value_type type; }; template< typename KeywordTagT1, typename ArgT, typename KeywordTagT2 > struct parameter_type< aux::tagged_argument< KeywordTagT1, ArgT >, KeywordTagT2 > { typedef void type; }; template< typename ArgT, typename TailT, typename KeywordTagT > struct parameter_type< aux::arg_list< aux::tagged_argument< KeywordTagT, ArgT >, TailT >, KeywordTagT > { typedef typename aux::tagged_argument< KeywordTagT, ArgT >::value_type type; }; template< typename KeywordTagT1, typename ArgT, typename TailT, typename KeywordTagT2 > struct parameter_type< aux::arg_list< aux::tagged_argument< KeywordTagT1, ArgT >, TailT >, KeywordTagT2 > : public parameter_type< TailT, KeywordTagT2 > { }; } // namespace parameter namespace conversion { namespace keywords { BOOST_PARAMETER_KEYWORD(tag, source) BOOST_PARAMETER_KEYWORD(tag, default_) BOOST_PARAMETER_KEYWORD(tag, radix) BOOST_PARAMETER_KEYWORD(tag, bool_alpha) } // namespace keywords // Some traits to aid string-related conversion template< typename T > struct is_string : mpl::false_ {}; template< > struct is_string< std::string > : mpl::true_ {}; // Conversion tags struct string_to_integral_tag {}; struct integral_to_string_tag {}; template< typename FromT, typename ToT > typename enable_if< mpl::and_< is_string< FromT >, is_integral< ToT > >, string_to_integral_tag >::type get_conversion_tag(FromT*, ToT*); template< typename FromT, typename ToT > typename enable_if< mpl::and_< is_integral< FromT >, is_string< ToT > >, integral_to_string_tag >::type get_conversion_tag(FromT*, ToT*); template< typename FromT, typename ToT > struct conversion_tag_of { typedef BOOST_TYPEOF_TPL(get_conversion_tag((FromT*)0, (ToT*)0)) type; }; // Converter functional object template< typename ToT, typename ConversionTagT > struct converter_impl; template< typename FromT, typename ToT > struct args_converter { typedef ToT result_type; typedef typename conversion_tag_of< FromT, ToT >::type conversion_tag; template< typename ArgsT > result_type operator() (ArgsT const& args) const { converter_impl< ToT, conversion_tag > impl; return impl(args); } template< typename ArgsT > result_type operator() (FromT const& from, ArgsT const& args) const { converter_impl< ToT, conversion_tag > impl; return impl((args, keywords::source = from)); } }; template< typename FromT, typename ToT > struct converter : public std::unary_function< FromT, ToT > { typedef typename std::unary_function< FromT, ToT >::result_type result_type; typedef typename conversion_tag_of< FromT, ToT >::type conversion_tag; private: boost::function1< result_type, FromT const& > m_Converter; public: template< typename ArgsT > explicit converter(ArgsT const& args) : m_Converter(boost::bind(args_converter< FromT, ToT >(), _1, args)) { } result_type operator() (FromT const& from) const { return m_Converter(from); } }; // This function should be declared with Boost.Parameter macros template< typename ToT, typename ArgsT > inline ToT convert(ArgsT const& args) { typedef typename parameter::parameter_type< ArgsT, keywords::tag::source >::type from_type; args_converter< from_type, ToT > conv; return conv(args); } // String-to-integral conversion template< typename ToT > struct converter_impl< ToT, string_to_integral_tag > { typedef ToT result_type; template< typename ArgsT > ToT operator() (ArgsT const& args) const { std::istringstream strm(args[keywords::source]); if (args[keywords::bool_alpha | false]) { strm >> std::boolalpha; } switch (args[keywords::radix | 10]) { case 16: strm >> std::hex; break; case 8: strm >> std::oct; break; } ToT result = args[keywords::default_]; strm >> result; return result; } }; // Integral-to-string conversion template< typename ToT > struct converter_impl< ToT, integral_to_string_tag > { typedef ToT result_type; template< typename ArgsT > ToT operator() (ArgsT const& args) const { std::ostringstream strm; if (args[keywords::bool_alpha | false]) { strm << std::boolalpha; } switch (args[keywords::radix | 10]) { case 16: strm << std::hex; break; case 8: strm << std::oct; break; } strm << args[keywords::source]; if (strm.good()) return strm.str(); else return args[keywords::default_]; } }; } // namespace conversion } // namespace boost int main(int, char*[]) { using namespace boost::conversion; // After utilizing Boost.Parameter macros the double parenthesis will not be needed, // and the "source" parameter will be able to be specified without the "source" keyword. std::string s = convert< std::string >(( keywords::source = 100, keywords::radix = 16, keywords::default_ = "[error]")); int n = convert< int >(( keywords::source = s, keywords::radix = 16, keywords::default_ = -1)); std::cout << "s = '" << s << "', n = " << n << std::endl; boost::array< int, 5 > ints = { 10, 20, 30, 40, 50 }; std::vector< std::string > strings; std::transform(ints.begin(), ints.end(), std::back_inserter(strings), converter< int, std::string >((keywords::radix = 16, keywords::default_ = "[error]"))); std::copy(strings.begin(), strings.end(), std::ostream_iterator< std::string >(std::cout, ", ")); std::cout << std::endl; return 0; }