10 Temmuz 2016 Pazar

boost variant

Variant Sınıfı
variant Sınıfı yazısına taşıdım.
Visitor
Şu satırı dahil ederiz.
#include <boost/variant.hpp> 
Visitor Tanımlama
Visitor şöyle tanımlanır. Visitor variant içindeki tüp tipler için bir operator()(X) tanımlamalıdır. Yoksa derleme hatası alırız.
struct as_int_visitor : boost::static_visitor<int> {
    int operator()(std::string const& s) const { return std::stoi(s); }
    int operator()(int i)                const { return i; }
};
void dönen visitor şöyle tanımlanır.
struct visitor : boost::static_visitor<>
{
  void operator()(const int& i) const { ... }
  void operator()(const std::string & str) const { ... }
};
Template Visitor Tanımlama
Template kullanan visitor şöyle tanımlanır.
struct GetVector : public boost::static_visitor<double>
{
  template<typename T>
  double operator() (const T& v)
  {...}
};
Template birden fazla parametre alabilir.
struct ADD {};
struct DEL {};

class MultiVisitor : public boost::static_visitor<void> {
  public:
    template <typename T, typename U>
    void operator()(T& t, const U& u) {
      t.visit(u);
    }
};

static MV const add = ADD();
static MV const del = DEL();

MultiVisitor mv;

for (TShapes& shape : tshapes) {
  boost::apply_visitor(mv, shape, add);
  boost::apply_visitor(mv, shape, del);
}
Polymorphic Functor ya da Template Functor
Örnek 1
İstersek bazı template tipleri için metod yazıp geri kalanını hep aynı yere yönlendirebiliriz. Şöyle yaparız.
struct IsNullThing {
  bool operator()(Null) const { return true; }
  template <typename T> bool operator()(T) const { return false; }

  template <typename... Ts> bool operator()(boost::variant<Ts...> const& v) const{
    return boost::apply_visitor(*this, v);
  }
 };
Bunu şöyle kullanırız.
IsNullThing isNullThing;

// and just call it

MyVariant v;
bool ok = isNullThing(v);
Örnek 2
Functor return type tanımlanması isteyebilir. Örneğin tüm tiplere ++ işlemi yapmak istersek şöyle yaparız.
namespace detail {
struct incrementer {
    template< typename T >
    void operator()(T& x) const { ++x; }
    typedef void result_type;
};
}

void incr(AnyIterator& ai)
{
  boost::apply_visitor(detail::incrementer(),ai);
}
Örnek 3
bool tipi için Add işlemini gerçekleştiremeyen bir polymorphic functor yazmak için şöyle yaparız.
struct Add : public boost::static_visitor<VariantType> {
  template <typename T, typename U>
  auto operator() (T a, U b) const -> decltype(a+b) { return a + b; }

  template <typename T> VariantType operator()(bool, T) const { 
    throw std::invalid_argument("Can't to bool"); }
  template <typename T> VariantType operator()(T, bool) const { 
    throw std::invalid_argument("Can't add bool"); }
  VariantType                     operator()(bool,bool) const { 
    throw std::invalid_argument("Can't add bools"); }
};
Şöyle çağırırız.
using VariantType = boost::variant<int, float, double, bool>;

int main() {
  std::cout << std::boolalpha;

  VariantType specimens[] = { int(42), 3.14f, 3.14, true };
  for (auto lhs : specimens)
    for (auto rhs : specimens)
    {
      try {
        std::cout << lhs << " + " << rhs << " ==  " <<
           boost::apply_visitor(Add{}, lhs, rhs) << "\n";
      } catch(std::exception const& e) {
        std::cout << lhs << " + " << rhs << " ==> " << e.what() << "\n";
    }
  }
}
Çıktı olarak şunu alırız.
42 + 42 ==  84
42 + 3.14 ==  45.14
42 + 3.14 ==  45.14
42 + true ==> Can't add bool
3.14 + 42 ==  45.14
3.14 + 3.14 ==  6.28
3.14 + 3.14 ==  6.28
3.14 + true ==> Can't add bool
3.14 + 42 ==  45.14
3.14 + 3.14 ==  6.28
3.14 + 3.14 ==  6.28
3.14 + true ==> Can't add bool
true + 42 ==> Can't to bool
true + 3.14 ==> Can't to bool
true + 3.14 ==> Can't to bool
true + true ==> Can't add bools
Visitor Çağırma
Şöyle çağrılır.
boost::apply_visitor(some_visitor(), myvariant);
Daha kolay çağırma için genelde yardımcı bir metod kullanılır.
int as_int(StringOrInt const& v) {
    return apply_visitor(as_int_visitor{}, v);
}
Şöyle çağırırız.
for (int i = values.size()-1; i > 0; --i)
  std::cout << as_int(values[i]);
C++14 ile Template Lambda
Tüm nesnelerin somet_operation metodu olduğunu varsayarak şöyle yaparız.
boost::apply_visitor([](auto const& obj) { obj.some_operation(); }, v);










Hiç yorum yok:

Yorum Gönder