Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
template <class F, class... X>
using apply = typename F::template call<X...>::value;
struct And {
template <class X, class... Y>
struct call;
};
template <class X>
struct And::call<X> {
using value = X;
};
template <class X, class... Y>
struct And::call<Zero, X, Y...> {
using value = Zero;
};
template <class X, class... Y>
struct And::call<One, X, Y...> {
using value = apply<And, X, Y...>;
};
#include <iostream>
template <class F, class... X>
using apply = typename F::template call<X...>::value;
template <class T>
struct Identity {
template <class...>
struct call {
using value = T;
};
};
struct One : Identity<One> {
};
struct Zero : Identity<Zero> {
};
struct Nil : Identity<Nil> {
};
struct Not {
template <class X>
struct call;
};
template <>
struct Not::call<Zero> {
using value = One;
};
template <>
struct Not::call<One> {
using value = Zero;
};
struct And {
template <class X, class... Y>
struct call;
};
template <class X>
struct And::call<X> {
using value = X;
};
template <class X, class... Y>
struct And::call<Zero, X, Y...> {
using value = Zero;
};
template <class X, class... Y>
struct And::call<One, X, Y...> {
using value = apply<And, X, Y...>;
};
template <class H, class T>
struct Cons : Identity<Cons<H, T>> {
};
struct Head {
template <class>
struct call;
};
template <class H, class T>
struct Head::call<Cons<H, T>> {
using value = H;
};
struct Tail {
template <class>
struct call;
};
template <class H, class T>
struct Tail::call<Cons<H, T>> {
using value = T;
};
struct List {
template <class...>
struct call;
};
template <>
struct List::call<> {
using value = Nil;
};
template <class H, class... T>
struct List::call<H, T...> {
using value = Cons<H, apply<List, T...>>;
};
struct Map {
template <class T, class F>
struct call;
};
template <class H, class T, class F>
struct Map::call<Cons<H, T>, F> {
using value = Cons<apply<F, H>, apply<Map, T, F>>;
};
template <class F>
struct Map::call<Nil, F> {
using value = Nil;
};
std::ostream& operator<<( std::ostream& os, One )
{
os << 1;
return os;
}
std::ostream& operator<<( std::ostream& os, Zero )
{
os << 0;
return os;
}
std::ostream& operator<<( std::ostream& os, Nil )
{
return os;
}
std::ostream& operator<<( std::ostream& os, And )
{
os << "&&";
return os;
}
template <class H, class T>
std::ostream& operator<<( std::ostream& os, Cons<H, T> )
{
os << "{ " << H() << " " << T() << "}";
return os;
}
int main()
{
std::cout << One() << std::endl;
// 1
std::cout << apply<And, One, One, One, One>() << std::endl;
// 1
std::cout << apply<And, One, One, Zero, One>() << std::endl;
// 0
using list = apply<List, One, One, Zero, One>;
std::cout << list() << std::endl;
// { 1 { 1 { 0 { 1 }}}}
std::cout << apply<Map, list, Not>() << std::endl;
//{ 0 { 0 { 1 { 0 }}}}
std::cout << apply<Map, list, One>() << std::endl;
//{ 1 { 1 { 1 { 1 }}}}
std::cout << apply<Map, list, Zero>() << std::endl;
//{ 0 { 0 { 0 { 0 }}}}
using list2 = apply<List, list, list>;
std::cout << apply<Map, list2, Tail>() << std::endl;
//{ { 1 { 0 { 1 }}} { { 1 { 0 { 1 }}} }}
std::cout << apply<Map, list2, One>() << std::endl;
//{ 1 { 1 }}
std::cout << apply<List, One, And, Zero>() << std::endl;
//{ 1 { && { 0 }}}
}
typedef рано или поздно приходится копипастить из-за того, что он остаётся там, где его определили.template <class T>
struct Eval {
template <class...>
struct call {
using value = T;
};
};
template <class... T>
struct Apply {
template <class...>
struct call;
};
template <class F, class... X>
struct Eval<Apply<F, X...>> {
template <class...>
struct call {
using value = apply<apply<Eval<F>>, apply<Eval<X>>...>;
};
};
template <class... T>
template <class...>
struct Apply<T...>::call {
using value = apply<Eval<Apply<T...>>>;
};
template <class F, class X>
struct Substitute {
template <class...>
struct call {
using value = F;
};
};
template <class X>
struct Substitute<X, X> {
template <class Y>
struct call {
using value = Y;
};
};
template <template <class...> class F, class... T, class X>
struct Substitute<F<T...>, X> {
template <class Y>
struct call {
using value = F<apply<Substitute<T, X>, Y>...>;
};
};
template <class X, class F>
struct Lambda {
template <class Y>
struct call {
using value = apply<Eval<apply<Substitute<F, X>, Y>>>;
};
};
template <class X, class F>
struct Eval<Lambda<X, F>> {
template <class...>
struct call {
using value = Lambda<X, F>;
};
};
struct X{};
using lambda = Lambda<X, Apply<List, X>>;
using result = apply<lambda, One>; // Cons<One, Nil>
impure {
#include <iostream>
template <typename T>
struct id {
typedef T _value;
};
}
x = impure {
x() { std::cout << "x"; }
}
y = id(x);
impure {
int main() {
impure y();
}
}
#include <iostream>
template <typename T>
struct id {
typedef T _value;
};
struct x {
x() { std::cout << "x"; }
};
typedef typename id <x> ::_value y;
int main() {
y();
}
Есть и подобные изыскания на этот счёт :)
Например: https://github.com/gergoerdi/metafun/
Эзотерический язык, транслирующийся в шаблоны C++