Sorry if this case is rather complicated, but I hope it helps people to better understanding modern c++ usage. So I want to make this code works. It should produce special lambdas for single integral type and for variant type for calculate sequence of terms on hard static cast to single type or on soft variant cast to common type, while this terms will be using. I add comments which describes what I really try to do in this code.
#include <variant>
#include <type_traits>
#include <string>
#include <functional>
#include <iostream>
#include <memory>
#include <optional>
#include <any>
#include <utility>
/* Visitor */
// Should get values from a variant
template <class... Ts>
struct Visitor;
template <class T, class... Ts>
struct Visitor<T, Ts...> : T, Visitor<Ts...> {
Visitor(T t, Ts... rest) : T(t), Visitor<Ts...>(rest...) {}
using T::operator();
using Visitor<Ts...>::operator();
};
template <class T>
struct Visitor<T> : T {
Visitor(T t) : T(t) {}
using T::operator();
};
/* Calculator */
// Should get special lambda for same type integrals and for variant packed integrals
template<class T, class... Ts>
class Calculator {
public:
// lambda for simple calculate same type integrals
static auto sum = [](T a, T b) { return a + b; };
// api for get current value of variant
template<typename... Vs>
static auto variant_value(std::variant<Vs...> v) {
return std::visit(Visitor<Vs...>{}, v);
}
// lambda for unpack variant arguments calc common value and pack in variant again
template<typename... Vs>
static auto variant_sum = [](std::variant<Vs...> a, std::variant<Vs...> b) {
auto value = variant_value<Vs...>(a) + variant_value<Vs...>(b);
return std::variant<Vs...>(value);
};
};
/* Term Producer */
namespace term::legion {
using std::function, std::any;
template<typename T>
function<any(any)> legion(auto& algebra) noexcept { // std::function<T(T,T...)
function<any(any)> redex = [](std::any a) {return a;};
// I delete code here because its not important now
return redex;
}
// production lamda for single type values
template<typename T>
std::function<std::any(std::any)> sum(T arg) noexcept {
return legion<T>(Calculator<T>::sum);
};
// production lambda for variant type values
template<typename ...Vs>
std::function<std::any(std::any)> sum() noexcept {
std::cout << "variant sum selected" << std::endl;
return legion<std::variant<Vs...>>(Calculator<Vs...>::template variant_sum<Vs...>);
};
}
int main() {
// term contains lambda for single type
auto sm = term::legion::sum<int>();
// term contains lambda for variant type
auto v_sm = term::legion::sum<char, int16_t, double>();
}