mercredi 5 janvier 2022

C++11 : Cast std::tuple type to void* and back

In summary, I would like to know how to properly store a std::tuple type as void* and later convert it back into the matching std::tuple type.

Problem, my program is currently crashing on the attempted cast from void* back to the matching std::tuple type as shown in B::fcn.

I believe the code below captures the essence of what I would like to be able to do. A bit of context, the reason I need to use the dreaded void* is because I have a data exchange layer where models can push and pull data to another model given they have the pointer to the target model. The data exchange layer does not support std::tuple type but does provide a ditch effort to support any type through pushing and pulling void*. If it were up to me I would convert the data exchange layer to be templated so that it could directly support std::tuple of any type but this is not an option.

    #include <iostream>
    #include <string>
    #include <vector>
    #include <tuple>

    /* Variadic method for streaming std::vector type to cout */
    template<typename T>
    std::ostream& operator<<(std::ostream& stream, std::vector<T> r)
    {
        //Save repetitive calls to check .size()
            int container_size = r.size();
            
        //Pre-allocate loop iterator
            int indx = 0;
            
        //Check if the input vector is empty
            if( container_size > 0 )
            {
                //Stream character for the start of a container
                    stream << "{ ";
                    
                    //For each element of the input container, could be a value or nested container
                        for(indx; indx < container_size; indx++)
                        {
                            //Execute based on iterator position within container
                                if( indx < ( container_size - 1 ) )
                                {
                                    //Print value, or recurse nested container to << template
                                        stream << r[ indx ] << ", ";
                                }
                                else
                                {
                                    //Stream last value and terminate with character
                                        stream << r[ indx ] << " }";
                                }
                        }
            }
            
        //Default & final execution
            return stream;
            
    };

    /* Start: Recursive variadic methods for streaming std::tuple type to cout */
    template <size_t n, typename... T>
    typename std::enable_if<(n >= sizeof...(T))>::type
    print_tuple(std::ostream&, const std::tuple<T...>&)
    {}

    template <size_t n, typename... T>
    typename std::enable_if<(n < sizeof...(T))>::type
    print_tuple(std::ostream& os, const std::tuple<T...>& tup)
    {
        if (n != 0)
            os << ", ";
        os << std::get<n>(tup);
        print_tuple<n+1>(os, tup);
    }

    template <typename... T>
    std::ostream& operator<<(std::ostream& os, const std::tuple<T...>& tup)
    {
        os << "[";
        print_tuple<0>(os, tup);
        return os << "]";
    }
    /* End: Recursive variadic methods for streaming std::tuple type to cout */

    /* An tuple alias for brevity */
    using MyType = std::tuple< int, std::vector<std::string> >;

    /* Dummy class for making an std::tuple and returning it as a void* */
    class A
    {
        public:
            void* fcn()
            {
                void *val;
                int p1 = 123;
                std::vector<std::string> p2 = { "Hello", "World" };
                MyType p3 = std::make_tuple( p1, p2 );
                val = &p3;
                return val;
            }
    };

    /* Dummy class for: receiving a void* and converting it to the expected type aliased as MyType; streaming private data member to cout */
    class B
    {
        public:
            void fcn(void *x)
            {
                p1 = *static_cast< MyType* >(x);
            }
            
            void print()
            {
                std::cout<<"\nP1 = "<<p1<<"\n";
            }
        
        private:
            MyType p1;
    };

    /* Main program */
    int main()
    {         
        //Make instance of class A
            A a;
        
        //Make instance of class B
            B b;
            
        //Test: std::tuple -> void* -> std::tuple
            b.fcn( a.fcn() );
            
        //Test: print private data member of B
            b.print();
        
        //Exit main program 
            return 0;
        
    }

Aucun commentaire:

Enregistrer un commentaire