27 Eylül 2018 Perşembe

Variadic Template C++17

Giriş
fold expression kullanır. Gramer şöyle
fold-expression:
  ( cast-expression fold-operator ... )
  ( ... fold-operator cast-expression )
  ( cast-expression fold-operator ... fold-operator cast-expression )
fold-operator: one of
  +   -   *   /   %   ^   &   |   <<   >> 
  +=  -=  *=  /=  %=  ^=  &=  |=  <<=  >>=  =
  ==  !=  <   >   <=  >=  &&  ||  ,    .*   ->*
left binary fold ve right binary fold şöyledir.
(pack op ... op init)
(init op ... op pack)
Kolaylık
Fold expression C++17 ile geliyor. C++11 ile özyinelemeli kod yazmak gerekiyordu.
void pack(std::vector<uint8_t> &) {}

template<typename T, typename... Args>
void pack(std::vector<uint8_t> &buffer, T first, Args... args) {
  buffer << first;
  pack(buffer, args ...);
}
C++17 ile recursion yani özyineleme yapmak gerekmiyor.
Kalıtım
Elimizde belirtilen her parametreden kalıtan ve hee parametre için oeprator() tanımlayan bir sınıf olsun.
template<class... Ts>
struct overloaded : Ts... 
 { using Ts::operator()...; };
Bu sınıfı yaratabilmek için şöyle yaparız.
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
Yaratmayayı çağırmak için şöyle yaparız.
auto ov = overloaded{ arg1, arg2, arg3, arg4 };
Ya da şöyle yaparız.
overloaded ov{ arg1, args, arg3, arg4 };
Ya da şöyle yaparız.
overloaded{
            [](auto arg) { std::cout << arg << ' '; },
            [](double arg) { std::cout << std::fixed << arg << ' '; },
            [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
            }
Bu durumda şu kod çalışır.
#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>

using var_t = std::variant<int, long, double, std::string>;

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;

int main() {
    std::vector<var_t> vec = { 10, 15l, 1.5, "hello" };
    for (auto& v : vec) {
        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);
    }
}
unary right fold
Variadic Template Unary Right Fold yazısına taşıdım.

unary left fold
Variadic Template Unary Left Fold yazısına taşıdım