C++,
pasted
on Feb 24:
|
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
#include <algorithm>
#include <functional>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/parameter/keyword.hpp>
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
namespace
user
{
struct
uuid
{
unsigned char value_[16];
};
}
namespace
boost
{
namespace
conversion
{
struct uuid_to_string_tag {};
template <typename ToT>
typename
enable_if<
is_string< ToT >,
uuid_to_string_tag >::type
get_conversion_tag( user::uuid*, ToT* );
template <>
struct
converter_impl<user::uuid,uuid_to_string_tag>
{
typedef std::string result_type;
result_type
operator()() const
{
return std::string("Test");
}
};
}
}
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;
user::uuid u;
std::cout << convert<std::string>((keywords::source=u));
return 0;
}
|
Output:
|
cc1plus: warnings being treated as errors
In function 'int main(int, char**)':
Line 296: warning: missing braces around initializer for 'int [5]'
t.cpp: At global scope:
t.cpp: In instantiation of 'boost::conversion::conversion_tag_of<user::uuid, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >':
t.cpp:124: instantiated from 'boost::conversion::args_converter<user::uuid, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >'
t.cpp:167: instantiated from 'ToT boost::conversion::convert(const ArgsT&) [with ToT = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, ArgsT = boost::parameter::aux::tagged_argument<boost::conversion::keywords::tag::source, user::uuid>]'
t.cpp:308: instantiated from here
Line 112: error: no matching function for call to 'get_conversion_tag(user::uuid*, std::basic_string<char, std::char_traits<char>, std::allocator<char> >*)'
compilation terminated due to -Wfatal-errors.
|
|