Skip to content

Instantly share code, notes, and snippets.

@Garciat
Last active January 24, 2026 21:48
Show Gist options
  • Select an option

  • Save Garciat/dae707beb822d191447ce9dcdb61ab61 to your computer and use it in GitHub Desktop.

Select an option

Save Garciat/dae707beb822d191447ce9dcdb61ab61 to your computer and use it in GitHub Desktop.
#include <memory>
#include <print>
#include <sstream>
#include <string>
#include <variant>
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
auto format(auto&& value) {
std::ostringstream os;
os << value;
return os.str();
}
template <typename... Ts>
auto format(std::variant<Ts...> v) {
return std::visit([](auto&& item) -> auto {
return format(item);
}, v);
}
template <typename T>
T formula(T x, T y) {
return 10 + x * 8 + x * y + 5;
}
template <typename T>
using Ptr = std::shared_ptr<T>;
struct Expr {
struct Var { std::string name; };
struct Add { Ptr<Expr> lhs, rhs; };
struct Mul { Ptr<Expr> lhs, rhs; };
struct Lit { std::variant<int, double> value; };
std::variant<Var, Add, Mul, Lit> data;
static Ptr<Expr> var(std::string name) {
return std::make_shared<Expr>(Expr{Var{name}});
}
static Ptr<Expr> add(Ptr<Expr> lhs, Ptr<Expr> rhs) {
return std::make_shared<Expr>(Expr{Add{lhs, rhs}});
}
static Ptr<Expr> mul(Ptr<Expr> lhs, Ptr<Expr> rhs) {
return std::make_shared<Expr>(Expr{Mul{lhs, rhs}});
}
static Ptr<Expr> lit(decltype(Lit::value) item) {
return std::make_shared<Expr>(Expr{Lit{item}});
}
};
std::string pp(Ptr<Expr> expr) {
return std::visit(overloaded{
[](Expr::Var var) -> std::string {
return var.name;
},
[](Expr::Add add) -> std::string {
return "(" + pp(add.lhs) + " + " + pp(add.rhs) + ")";
},
[](Expr::Mul mul) -> std::string {
return "(" + pp(mul.lhs) + " + " + pp(mul.rhs) + ")";
},
[](Expr::Lit lit) -> std::string {
return format(lit.value);
},
}, expr->data);
}
Ptr<Expr> operator+(Ptr<Expr> lhs, Ptr<Expr> rhs) {
return Expr::add(lhs, rhs);
}
Ptr<Expr> operator*(Ptr<Expr> lhs, Ptr<Expr> rhs) {
return Expr::mul(lhs, rhs);
}
template <typename T>
Ptr<Expr> operator+(Ptr<Expr> lhs, T rhs) {
return Expr::add(lhs, Expr::lit(rhs));
}
template <typename T>
Ptr<Expr> operator+(T lhs, Ptr<Expr> rhs) {
return Expr::add(Expr::lit(lhs), rhs);
}
template <typename T>
Ptr<Expr> operator*(Ptr<Expr> lhs, T rhs) {
return Expr::mul(lhs, Expr::lit(rhs));
}
template <typename T>
Ptr<Expr> operator*(T lhs, Ptr<Expr> rhs) {
return Expr::mul(Expr::lit(lhs), rhs);
}
int main() {
std::println("{}", pp(formula(Expr::var("x"), Expr::var("y"))));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment