2012-11-15 11 views
5

मुझे यह https://gist.github.com/2945472 मिला लेकिन मुझे एक कार्यान्वयन की आवश्यकता है जो सी ++ 11 पर निर्भर नहीं है। मैंने इसे केवल बढ़ावा देने के लिए परिवर्तित करने के लिए अपने हाथ की कोशिश की, लेकिन मुझे कुछ परेशानी हो रही है।बूस्ट के लिए आगंतुक पैटर्न :: कोई

#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 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> void insert_visitor(boost::function<void(T)> f) { 
     try { 
      fs.insert(std::make_pair(boost::ref(typeid(T)), boost::bind(f, boost::any_cast<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 & x : xs) { 
     if (!f(x)) std::cout << "no visitor registered" << std::endl; 
    } 
} 

जब नक्शा में डालने मैं एक bad_any_cast हो रही है:

यहाँ मैं के साथ आया है। किसी भी_कास्ट को केवल इसके द्वारा बुलाया नहीं जाना चाहिए-> दूसरा (x)? मैं क्या गलत कर रहा हूं?

+0

क्या आपने 'boost :: variant' का उपयोग करने पर विचार किया है जिसके लिए आगंतुकों को बॉक्स से बाहर समर्थित किया जाता है? 'किसी भी' का उपयोग यह मानता है कि प्रकार * कुछ * हो सकते हैं, जो * सभी प्रकार के प्रकार सिस्टम में हैं। 'variant' मानता है कि उस प्रकार का सबसेट है जिसे आप ऑब्जेक्ट में उपयोग करना चाहते हैं। एक आगंतुक 'variant' के करीब है क्योंकि विभिन्न कार्यों को परिभाषित किया जाना चाहिए। –

+0

मेरा इरादा बूस्ट :: program_options से कॉन्फ़िगरेशन फ़ाइलों को लिखने के लिए इसका उपयोग करना है, जो boost :: किसी भी का उपयोग करता है। – Keith

उत्तर

3

आप _1 से T (बाइंड अभिव्यक्ति के समय) नहीं डाले जा सकते हैं।

आपको आलसी कलाकारों की आवश्यकता है। शायद एक फ़ंक्शन को परिभाषित करें और नेस्टेड बाइंड एक्सप्रेशन का उपयोग करें, या कस्टम any_cast अभिनेता के साथ बूस्ट फीनिक्स का उपयोग करें।

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

प्रिंटों उत्पादन: बढ़ाई किसी भी https://sourceforge.net/projects/extendableany/?source=directory उपयोग करने के लिए

fa(1) 
fb(abc()) 
no visitor registered 
+0

धन्यवाद, यह शानदार काम करता है! – Keith

+0

नोट मैंने टाइप_इनोफ_शैश फ़ैक्टर बॉडी को अपने सिस्टम पर संकलित करने के लिए प्रतिस्थापित किया है। नेस्टेड बाइंड एक्सप्रेशन रॉक, हालांकि :) – sehe

+0

ऐसा लगता है कि जब मैं इस पर काम कर रहा था तो मैं -std = C++ 11 ध्वज को हटाना भूल गया था। मुझे अपनी खुद की type_info हैशकोड विधि लिखनी होगी। मैं मुख्य रूप से लूप में 'ऑटो' को हटाने में भी चूक गया। – Keith

1

कोशिश

यहाँ नेस्टेड बाँध तरीका है।

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(); 
} 
संबंधित मुद्दे