Generic function to convert boost::any to boost::variant

前端 未结 2 1880
轮回少年
轮回少年 2020-12-21 05:19

Assume that you have a boost::any object and a boost::variant object.

I\'m looking for a generic function convert, that takes

2条回答
  •  感动是毒
    2020-12-21 06:17

    You can call boost::any_cast for each of the types within boost::variant and stop when the first cast succeeded:

    #include 
    #include 
    #include 
    #include 
    
    #include 
    #include 
    #include 
    #include 
    #include 
    
    template 
    struct mpl_sequence_to_std_tuple
    {
    template 
    static auto x(std::index_sequence) -> std::tuple::type...>;
    
    using type = decltype(x(std::make_index_sequence::type::value>{}));
    };
    
    struct signal_conversion_success{};
    
    template 
    void try_convert(const boost::any& any, Variant& var)
    {
        try
        {
            var = boost::any_cast(any);
            throw signal_conversion_success{};
        }
        catch(const boost::bad_any_cast &)
        {
        }
    }
    
    template 
    std::string parameter_pack_to_string(const std::string& separator = ", ")
    {
        std::stringstream ss;
        ss << boost::typeindex::type_id().pretty_name();
        auto l = {0, (void(ss << separator << boost::typeindex::type_id().pretty_name()),0)...};
        std::ignore = l;
        return ss.str();
    }
    
    template 
    void do_convert(const boost::any& any, Variant& var, std::tuple)
    {
        bool success = false;
    
        try {
            auto l = {0, (void(try_convert(any, var)), 0)... };
            std::ignore = l;
        }
        catch(const signal_conversion_success&)
        {
            success = true;
        }
    
        if (!success)
        {
            std::stringstream ss;
            ss << "cannot convert this boost::any instance to any of the following types: ";
            ss << parameter_pack_to_string();
            throw std::invalid_argument(ss.str());
        }
    }
    
    template
    void convert(const boost::any& any, Variant& var)
    {
      using Tuple = typename mpl_sequence_to_std_tuple::type;
      do_convert(any, var, Tuple{});
    }
    
    struct print_visitor : public boost::static_visitor
    {
        template 
        void operator()(T&& t) const
        {
            std::cout << boost::typeindex::type_id().pretty_name() << ": " << std::forward(t) << std::endl;
        }
    };
    
    int main()
    {
        using Variant = boost::variant;
        boost::any any = std::string("Hello World");
        Variant var;
        convert(any, var);
        boost::apply_visitor(print_visitor(), var);
    }
    

    live example

    In case none of the casts succeeded, an exception is thrown, see the following live example.

提交回复
热议问题