Container for boost::multi_array of same type but with different dimentionality

前端 未结 1 555
萌比男神i
萌比男神i 2020-12-21 16:52

What i need is to create a class that can hold boost::multi_array of same type but with different dimentions

assume there are one or more such arrays of Double

1条回答
  •  难免孤独
    2020-12-21 17:24

    Firstly, I think you may want to evaluate your design. Like with functors, it's rarely required to code semi-rigid type wrappers around your generic type arguments.

    However, if you do find you have a need for this, here's a solution that uses boost::variant:

    template 
    struct GenericArray
    {
        template  using array_t = boost::multi_array;
    
        template  GenericArray& operator=(Rhs&& rhs) {
            _storage = std::forward(rhs);
            return *this;
        }
    
        template  array_t      & get()       { return boost::get >(_storage); }
        template  array_t const& get() const { return boost::get >(_storage); }
    
      private:
        typename detail::make_generic_array_storage::type _storage;
    };
    

    The get<> member function throws a boost::bad_get exception if you get the dimension wrong at runtime.

    Now, the trick is, of course, how _storage is implemented. I generate a variant over a list of array dimensions using a bit of Boost MPL magic:

    namespace detail {
        namespace mpl = boost::mpl;
    
        template 
        struct make_generic_array_storage
        {
            template  using array_t = boost::multi_array;
            template struct to_array_f { typedef array_t type; };
    
            using list = typename mpl::transform<
                mpl::range_c, 
                to_array_f,
                mpl::back_inserter > 
            >::type;
    
            using type = typename boost::make_variant_over::type;
        };
    }
    

    Nothing overly complicated, if you look at it from a high level :)

    Next up: demo! See it Live On Coliru

    GenericArray arr;
    arr = array_3d;
    
    try { auto& ref3 = arr.get<3>(); }
    catch (boost::bad_get const& e) { std::cout << "L:" << __LINE__ << " " << e.what() << "\n"; }
    
    try { auto& ref2 = arr.get<2>(); } // this fails
    catch (boost::bad_get const& e) { std::cout << "L:" << __LINE__ << " " << e.what() << "\n"; }
    
    arr = array_2d;
    
    try { auto& ref2 = arr.get<2>(); } // this succeeds
    catch (boost::bad_get const& e) { std::cout << "L:" << __LINE__ << " " << e.what() << "\n"; }
    
    std::cout << "Done";
    

    Prints:

    L:58 boost::bad_get: failed value get using boost::get
    Done
    

    as expected.


    Bonus: To implement more array-like operations over the variant storage, have a look here:

    • Generating an interface without virtual functions?
    • How to create a interface for serialization in Boost Serialization?

    which touch on this topic

    0 讨论(0)
提交回复
热议问题