2012-11-15 16 views
5

Bu https://gist.github.com/2945472 buldum ama C++ 11 bağımlı olmayan bir uygulamaya ihtiyacım var. Elimi sadece güçlendirmeyi kullanmaya çevirmeye çalıştım, ama bazı sıkıntılarım var. haritayı eklerken bir bad_any_cast alıyorumziyaretçi forumu :: any

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

: Burada

ben ile geldi budur. Any_cast sadece buna göre değil -> second (x)? Neyi yanlış yapıyorum?

+0

Ziyaretçilerin kutudan desteklendiği "boost :: variant" kullanmayı düşündünüz mü? "Herhangi bir" kullanımı, türlerin * herhangi bir şey * olabileceğini varsayar; bu, sistemdeki * tüm * türlerdir. Varyant, nesnede kullanmak isteyebileceğiniz türlerin bir alt kümesi olduğunu varsayar. Farklı işlevlerin tanımlanması gerektiğinden, bir ziyaretçi bir varyanta daha yakındır. –

+0

Amacım, boost :: program_options dosyasından, config :: files_options komutunu yazmak için kullanmaktır. – Keith

cevap

3

_1'u T'a (ciltleme ifadesi sırasında) atayamazsınız.

Tembel bir oyuncuya ihtiyacınız var. Belki bir fonksiyon tanımlayın ve yuvalanmış bir bind ifadesi kullanın veya özel bir any_cast aktörüyle Boost Phoenix'i kullanın.

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

Baskılar çıktı: uzatılabilir herhangi https://sourceforge.net/projects/extendableany/?source=directory kullanmak

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

Teşekkür ederim, bu muhteşem bir şekilde çalışıyor! – Keith

+0

Not Sistemimde derlemek için type_info_hash functor gövdesini değiştirdim. İç içe geçmiş bağlama ifadeleri olsa da, rock :) – sehe

+0

Üzerinde çalıştığım zaman -std = C++ 11 bayrağını kaldırmayı unutmuşum gibi görünüyor. Kendi type_info hash_code yöntemimi yazmam gerekecek. Ayrıca ana döngüde 'auto' kaldırmayı özledim. – Keith

1

deneyin

Burada iç içe bağlama yaklaşımdır.

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(); 
} 
İlgili konular