2 Haziran 2017 Cuma

variant static_visitor Sınıfı

Her Tip İle Çalışacak Visitor
Elimizde bir variant olsun. variant ile kullanılan her tip getIntegerValue() ve getString() metodlarına sahip olsun
typedef boost::variant <...,...> MyVar;
Her tip ile çalışacak bir template visitor için şöyle yaparız.
struct MyVisitor : boost::static_visitor<void>
{
  template <typename T>
  void operator()(T& x) const
  {
    x.getIntegerValue());
    x.getString());   
  }
};
Şöyle yaparız.
MyVar variant = ...
MyVisitor visitor;
boost::apply_visitor (visitor, variant);
Bir Tip İle Çalışacak Visitor
Şöyle yaparız.
template<typename T>
class converter_visitor : public boost::static_visitor<>
{
public: 
  std::vector<T>& vec;

  converter_visitor(std::vector<T>& r) : vec(r) {}

  // only push back values of specific types...
  void operator()(const T& u) const {
    vec.push_back(u);
  }

  // ignore other types...
  void operator()(...) const {}  
};
Bu visitor'ı yaratmak için şöyle yaparız.
template<typename T>
converter_visitor<T> make_visitor(std::vector<T>& r)
{
  return converter_visitor<T>(r); 
}
Şöyle yaparız.
template<typename T,typename U>
void filter(std::vector<T>& result,const U& var) {
  boost::apply_visitor( make_visitor(result), var );
}

template<typename T,typename U>
void filter(std::vector<T>& result,const std::vector<U>& cont) {
  std::for_each(cont.begin(),cont.end(),[&](const U& c) {
        filter(result,c);
    });
}
Şöyle yaparız.
_vec_var v1;
v1.push_back(11);
v1.push_back(13);
v1.push_back("see ya");


std::vector<int> result;         
filter(result,vv);
Kalıtım ile Çalışacak Visitor
Variant içinde hiyerarşik nesnelerin bulunması mantıklı değil, ancak böyle bir senaryo varsayalım. Visitor ile ata sınıfa pointer elde etmek için şöyle yaparız.
template<class Base>
struct poly_ptr_t:boost::static_visitor<Base*> {
  template<class T>
  Base* operator()(T& t)const { return std::addressof(t); }

  template<class...Ts>
  Base* operator[](boost::variant<Ts...>& v) const {
    return boost::apply_visitor( *this, v );
  }
  template<class...Ts>
  Base const* operator[](boost::variant<Ts...> const& v) const {
    return boost::apply_visitor( *this, v );
  }
};
Visitor'ın sonucunu kullanarak virtual metod çağırmak için şöyle yaparız.
poly_ptr_t<Polygon> as_polygon;
int main() {
  boost::variant<Triangle, Rectangle> u(Triangle{});
  as_polygon[u]->set_values(x,y);
}
Generic Lambda Visitor
Örnek
C++14 ile şöyle yaparız.
boost::apply_visitor([](auto& x){
  x.getIntegerValue());
  x.getString());      
}, variant);
Örnek
Şöyle yaparız.
boost::apply_visitor( [](auto& e){...}, variant);
Visitor ve Kalıtım
Önce bir ata sınıf tanımlarız.
template<class Derived, typename T>
struct BaseVisitor : public boost::static_visitor<T> {
  using typename boost::static_visitor<T>::result_type;

  Derived & derived() { return static_cast<Derived &>(*this); } 

  result_type operator()(const NextVar& n) {
    return n.apply_visitor( derived() );
  }
  template<int I>
  result_type operator()(const A<I>& a)  {
    return derived().visit(a);
  }
};
Daha sonra kalıtan sınıfı yazarız. Şöyle yaparız.
struct PrintVisitor : public BaseVisitor<PrintVisitor, std::string> {
  template<int I>
  std::string visit(const A<I>& a)  {
    return std::to_string(a.value);
  }
};


Hiç yorum yok:

Yorum Gönder