9 Ocak 2018 Salı

std::visit

Giriş
Şu satırı dahil ederiz.
#include <variant>
Birinc parametre overloaded metodu, ikinci parametre ise variant nesnesidir.

Örnek
Şöyle yaparız.
bool input = ...;

std::variant<int, long, double, std::string> myVariant;
if(input)
  myVariant = "Example1";
else
  myVariant = 3.14;

std::visit([](auto&& arg) { std::cout << arg << std::endl; }, myVariant);
Örnek
Tipe göre farklı iş yapmak için şöyle yaparız.
std::variant<int, long, double, std::string> v = ...;

std::visit(overloaded {
  [](auto arg) { std::cout << arg << ' '; },
  [](double arg) { std::cout << std::fixed << arg << ' '; },
  [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
}, v);
Örnek
Elimizde variant dönen bir metod olsun.
#include <variant>
#include <string>

struct CellNotFound {};
struct Cell {};

using CellFindResult = std::variant<CellNotFound, Cell>;


CellFindResult Find(std::string segment) {
  CellFindResult result { CellNotFound {} };

  // Search code here.
  return result;
}
Metodun sonucuna göre farklı iş yapmak için şöyle yaparız.
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

void cellsAndStuff()
{
  std::visit(overloaded
  {
    [&](CellNotFound)
    {
      // the not-found code
    },
    [&](Cell c)
    {
      // code on cell found
    }
  }, Find("foo"));
}
Örnek
if kullanmak için şöyle yaparız.
template <typename T, typename... Args>
struct is_one_of: 
    std::disjunction<std::is_same<std::decay_t<T>, Args>...> {};

std::visit([](auto&& arg) {
  static_assert(is_one_of<decltype(arg), 
                          int, long, double, std::string>{}, "Non matching type.");
  using T = std::decay_t<decltype(arg)>;
  if constexpr (std::is_same_v<T, int>)
    std::cout << "int with value " << arg << '\n';
  else if constexpr (std::is_same_v<T, double>)
    std::cout << "double with value " << arg << '\n';
  else 
    std::cout << "default with value " << arg << '\n';
}, v);
Örnek
Variant değişirse derleme zamanı kontrol eklemek için şöyle yaparız.
template <typename... Args>
struct visit_only_for {
  // delete templated call operator
  template <typename T>
  std::enable_if_t<!is_one_of<T, Args...>{}> operator()(T&&) const = delete;
};

// then
std::visit(overloaded {
  visit_only_for<int, long, double, std::string>{}, // here
    [](auto arg) { std::cout << arg << ' '; },
    [](double arg) { std::cout << std::fixed << arg << ' '; },
    [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
}, v);
std::visit ve Return Type
Açıklaması şöyle
"The value returned by the selected invocation of the visitor, converted to the common type of all possible std::invoke expressions"
Yani visitor benzer tipler dönmeli. Klasik bir visitor'da şöyle yaparız.
struct Visitor {
  using some_type = /*...*/;

  some_type operator()(A const& a);
  some_type operator()(B const& b);
};
Örnek
Eğer farklı tipler döneceksek şöyle yaparız.
template <typename Visitor, typename ... Ts>
decltype(auto) my_visit(Visitor&& vis, const std::variant<Ts...>& var)
{
  return std::visit([&](auto&& e)
    -> std::common_type_t<decltype(vis(std::declval<Ts>()))...>
    {
      return vis(e);
    }, var);
}
Yeni bir variant dönebiliriz.Şöyle yaparız
struct Functor {
  std::variant<A,B> operator()(A const& a) const {
    return A{2*a.i};
  }
  std::variant<A,B> operator()(B const& b) const {
    return B{3*b.j};
  }
};




Hiç yorum yok:

Yorum Gönder