C++11:将 std::tuple 类型转换为 void* 并返回

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

总而言之,我想知道如何将 std::tuple 类型正确存储为 void* 并稍后将其转换回匹配的 std::tuple 类型。

问题,我的程序当前正在尝试从 void* 转换回匹配的 std::tuple 类型时崩溃,如 B::fcn 中所示。

我相信下面的代码抓住了我想做的事情的本质。一些上下文,我需要使用可怕的 void* 的原因是因为我有一个数据交换层,模型可以在其中将数据推送和拉取到另一个模型,因为它们具有指向目标模型的指针。数据交换层不支持 std::tuple 类型,但确实提供了通过推拉 void* 来支持任何类型的努力。如果由我决定,我会将数据交换层转换为模板,以便它可以直接支持任何类型的 std::tuple 但这不是一个选项。

    #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;
        
    }

fcn() 正在返回指向局部变量的悬空指针。 void*可以用来指向任何类型的对象,但是它不包含它所指向的对象的内存。要进行类型擦除,您需要一个存储或堆分配的内存来存储对象,然后用 void* 指向它并稍后将其强制转换回来,以及管理它所指向的内存。您可以查看 std::any 来管理任何类型的对象(基本上就是这样做的)。