visitor pattern for boost::any

前端 未结 2 462
盖世英雄少女心
盖世英雄少女心 2021-01-05 22:41

I found this https://gist.github.com/2945472 but I need an implementation that does not depend on c++11. I tried my hand at converting it to use only boost, but I\'m having

相关标签:
2条回答
  • 2021-01-05 23:24

    Try to use extendable any https://sourceforge.net/projects/extendableany/?source=directory.

    struct f_method
    {
        typedef void (boost::mpl::_1::* signature) () const;
    
        template <typename T>
        struct wrapper
            : public T
        {
            void f() const
            {
                return this->call(f_method());
            }
        };
    
        struct implementation
        {
            void operator() (int i) const
            {
               std::cout << "fa(" << i << ")" << std::endl;
            }
    
            void operator() (abc) const
            {
               std::cout << "fb(abc())" << std::endl;
            }
    
            template <typename T>
            void operator() (const T& t) const
            {
                std::cout << "Errr" << std::endl;
            }
        };
    };
    
    typedef xany<boost::mpl::list<f_method> > any;
    
    int main() {
        std::vector<any> xs;
        xs.push_back(1);
        xs.push_back(abc());
        xs.push_back(1.5);
    
        for (auto it=xs.begin(); it!=xs.end(); ++it)
            (*it).f();
    }
    
    0 讨论(0)
  • 2021-01-05 23:32

    You can't cast _1 to T (at the time of the bind expression).

    You need a lazy cast. Perhaps define a function and use a nested bind expression, or use Boost Phoenix with a custom any_cast actor.

    Here's the nested bind approach:

    #include <boost/any.hpp>
    #include <boost/function.hpp>
    #include <boost/bind.hpp>
    #include <boost/lambda/lambda.hpp>
    #include <boost/unordered_map.hpp>
    
    struct type_info_hash {
        std::size_t operator()(std::type_info const & t) const {
            return 42; // t.hash_code();
        }
    };
    
    struct equal_ref {
        template <typename T> bool operator()(boost::reference_wrapper<T> a,boost::reference_wrapper<T> b) const {
            return a.get() == b.get();
        }
    };
    struct any_visitor {
        boost::unordered_map<boost::reference_wrapper<std::type_info const>, boost::function<void(boost::any&)>, type_info_hash, equal_ref> fs;
    
        template <typename T> static T any_cast_f(boost::any& any) { return boost::any_cast<T>(any); }
    
        template <typename T> void insert_visitor(boost::function<void(T)> f) {
            try {
                fs.insert(std::make_pair(boost::ref(typeid(T)), boost::bind(f, boost::bind(any_cast_f<T>, boost::lambda::_1))));
            } catch (boost::bad_any_cast& e) {
                std::cout << e.what() << std::endl;
            }
        }
    
        bool operator()(boost::any & x) {
            boost::unordered_map<boost::reference_wrapper<std::type_info const>, boost::function<void(boost::any&)>, type_info_hash, equal_ref>::iterator it = fs.find(boost::ref(x.type()));
            if (it != fs.end()) {
                it->second(x);
                return true;
            } else {
                return false;
            }
        }
    };
    
    struct abc {};
    
    void fa(int i) { std::cout << "fa(" << i << ")" << std::endl; }
    void fb(abc) { std::cout << "fb(abc())" << std::endl; }
    
    int main() {
        any_visitor f;
        f.insert_visitor<int>(fa);
        f.insert_visitor<abc>(fb);
    
        std::vector<boost::any> xs;
        xs.push_back(1);
        xs.push_back(abc());
        xs.push_back(1.5);
    
        for (auto it=xs.begin(); it!=xs.end(); ++it)
            if (!f(*it)) std::cout << "no visitor registered" << std::endl;
    }
    

    Prints output:

    fa(1)
    fb(abc())
    no visitor registered
    
    0 讨论(0)
提交回复
热议问题