Search code examples
c++visual-c++boostboost-type-erasure

boost type erasure with multiple BOOST_TYPE_ERASURE_MEMBERs


I'm trying to get my head around the boost type erasure library. In particular, what if I want to declare an 'any' variable that accepts multiple BOOST_TYPE_ERASURE_MEMBERs.

My simple example below is trying to declare an any that accepts a class that has push_back and emplace_back - i.e. a vector. My production code is trying to wrap a complicated class with many members in an any.

When I try this, compiling with MSVC 2022, C++ 2017:

#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/any_cast.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/member.hpp>
#include <boost/type_erasure/free.hpp>
#include <boost/mpl/vector.hpp>
#include <vector>

namespace mpl = boost::mpl;
using namespace boost::type_erasure;

BOOST_TYPE_ERASURE_MEMBER(push_back)
BOOST_TYPE_ERASURE_MEMBER(emplace_back)

void aTest() {
    std::vector<int> b;
    any<
        mpl::vector<
            has_push_back<void(int)>,
            has_emplace_back<void(int)>
            >
 > a{b};

}


I get the following error message:

Severity Code Description Project File Line Suppression State Error C2440 'static_cast': cannot convert from 'const boost::type_erasure::detail::vtable_storage<boost::type_erasure::detail::vtable_adapter<PrimitiveConcept,void (boost::type_erasure::detail::storage &,int)>,boost::type_erasure::detail::vtable_adapter<has_emplace_back<void (int),boost::type_erasure::_self>,void (boost::type_erasure::detail::storage &,int)>> *' to 'const boost::type_erasure::detail::vtable_entryboost::type_erasure::destructible<T> *' BoostTestsMSVC D:\boost_msvc2022\boost_1_75_0\boost\type_erasure\detail\vtable.hpp 143

I have tried this:

void aTest() {
    std::vector<int> b;
    any<
        mpl::vector<
            has_push_back<void(int), const _self>,
            has_emplace_back<void(int), const _self>
            >
    > a{b};

and this:

void aTest() {
    std::vector<int> b;
    any<
        mpl::vector<
            has_push_back<void(int), const _self&>,
            has_emplace_back<void(int), const _self&>
            >
    > a{b};

but get the same error.

The boost basic examples show how to construct an any from one BOOST_TYPE_ERASURE_MEMBER declaration:

void aTest() {
    std::vector<int> b;
    any<has_push_back<void(int)>, _self&> container {b};

}

works fine.

But I want to use boost's type erasure for classes with many members that need to be accessible from the any class.

Any advice on how to do this would be much appreciated.

Andy


Solution

  • You didn't include the _self specifier for member functions. Any reason you left that off? The rest of the code looks like it was taken from the Basic Tutorial where it is shown.

    Adding it back makes it work:

    Live On Coliru

    #include <boost/type_erasure/any.hpp>
    #include <boost/type_erasure/any_cast.hpp>
    #include <boost/type_erasure/builtin.hpp>
    #include <boost/type_erasure/operators.hpp>
    #include <boost/type_erasure/member.hpp>
    #include <boost/type_erasure/free.hpp>
    #include <boost/mpl/vector.hpp>
    #include <iostream>
    
    BOOST_TYPE_ERASURE_MEMBER(push_back)
    BOOST_TYPE_ERASURE_MEMBER(emplace_back)
    
    template <typename T> struct NotVector {
        void push_back(T) { //
            std::cout << __PRETTY_FUNCTION__ << std::endl;
        }
    
        void emplace_back(T) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
    
        T dummy;
    };
    
    int main() {
        namespace mpl = boost::mpl;
        namespace te  = boost::type_erasure;
    
        using Any = te::any<                        //
            mpl::vector<has_push_back<void(int)>,   //
                        has_emplace_back<void(int)> //
                        >,
            te::_self&>;
    
        std::vector<int> a;
    
        {
            Any aa{a};
            aa.push_back(42);
            aa.emplace_back(42);
            assert(a == (std::vector{42, 42}));
        }
    
        {
            NotVector<int> b;
            Any            ab{b};
            ab.push_back(42);
            ab.emplace_back(42);
        }
    }
    

    Passes the assert and prints something like

    void NotVector<T>::push_back(T) [with T = int]
    void NotVector<T>::emplace_back(T) [with T = int]