[ create a new paste ] login | about

Link: http://codepad.org/WJNCaicE    [ raw code | output | fork ]

andysem - C++, pasted on Feb 25:
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
#include <algorithm>
#include <functional>
#include <boost/array.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, typename ArgsT >
struct bound_args_converter :
    public std::unary_function< FromT, ToT >
{
    typedef typename std::unary_function< FromT, ToT >::result_type result_type;

    explicit bound_args_converter(ArgsT const& args) : m_Args(args)
    {
    }

    result_type operator() (FromT const& from) const
    {
        args_converter< FromT, ToT > conv;
        return conv(from, m_Args);
    }

private:
    ArgsT m_Args;
};

// This function emulates the converter object
template< typename FromT, typename ToT, typename ArgsT >
inline bound_args_converter< FromT, ToT, ArgsT > converter(ArgsT const& args)
{
    return bound_args_converter< FromT, ToT, ArgsT >(args);
}

// 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];
};

struct uuid_to_string_tag {};

template< typename ToT >
typename boost::enable_if<
    boost::conversion::is_string< ToT >,
    uuid_to_string_tag
>::type get_conversion_tag(uuid*, ToT*);

} // namespace user

namespace boost {

namespace conversion {

template< typename ToT >
struct converter_impl< ToT, user::uuid_to_string_tag >
{
    typedef ToT result_type;

    template< typename ArgsT >
    ToT operator() (ArgsT const& args) const
    {
        return "Test";
    }
};

} // 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;
    ints[0] = 10;
    ints[1] = 20;
    ints[2] = 30;
    ints[3] = 40;
    ints[4] = 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) << std::endl;

    return 0;
}


Output:
1
2
3
s = '64', n = 100
a, 14, 1e, 28, 32, 
Test


Create a new paste based on this one


Comments: