2012-11-15 18 views
5

Znalazłem to https://gist.github.com/2945472, ale potrzebuję implementacji, która nie zależy od C++ 11. Próbowałem swoich sił w konwersji, by użyć tylko wzmocnienia, ale mam pewne kłopoty.wzór gościa dla boost :: any

Oto co wymyśliłem:

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

Dostaję bad_any_cast podczas wkładania do mapy. Czy nie powinno się wywoływać any_cast tylko przez niego-> sekundę (x)? Co ja robię źle?

+0

Czy rozważałeś użycie 'boost :: variant', dla którego użytkownicy są obsługiwani po wyjęciu z pudełka? Użycie 'any' zakłada, że ​​typy mogą być * cokolwiek *, czyli * wszystkie * typy w systemie typu. 'variant' zakłada, że ​​istnieje podzbiór typów, których możesz użyć w obiekcie. Odwiedzający jest bliżej "wariantu", ponieważ różne funkcje muszą być zdefiniowane. –

+0

Moim zamiarem jest użycie tego do wypisania plików konfiguracyjnych z boost :: program_options, który używa boost :: any. – Keith

Odpowiedz

3

Nie można rzucić _1 do T (w momencie wyrażenia powiązania).

Potrzebujesz leniwa obsada. Być może zdefiniuj funkcję i użyj zagnieżdżonego wyrażenia wiązania lub użyj funkcji Zwiększ Phoenix za pomocą niestandardowego aktora any_cast.

Oto zagnieżdżone podejście wiąże:

wyjście
#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; 
} 

Wydruki:

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

Dziękuję, to działa wspaniale! – Keith

+0

Uwaga I zastąpił ciało funktor type_info_hash, aby umożliwić jego kompilację w moim systemie. Zagnieżdżone wyrazy bindów, ale :) – sehe

+0

Wygląda na to, że zapomniałem usunąć flagę -std = C++ 11, kiedy pracowałem nad tym. Będę musiał napisać własną metodę hash_code type_info. Brakowało mi również usunięcia "auto" w pętli głównej. – Keith

1

Spróbuj skorzystać z wysuwaną żadnego 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(); 
} 
Powiązane problemy