Вот вчера после принятия "расширителя сознания" наваял такое.
Захотелось поиметь работу хотя-бы с базовыми функциями в compile-time — как например производная.
Вот что получилось:
main.cpp — пример использования
#include "PrintFunction.h"
#include "DeriveFunction.h"
#include "ValueFunction.h"
#include "SimplifyFunction.h"
#include <iostream>
using namespace std;
using namespace cm::fun;
using namespace cm::do_fun;
int main()
{
// описываем функцию
typedef Multiply<X, Cos<Sin<X> > > function;
// выведем ее
Print<function>::name(cout);
cout << endl << "--------------------------------" << endl;
// найдем производную функции
typedef Derive<function>::Result derive_function;
// упростим функцию
typedef ApplyNTimes<3, derive_function, Simplify>::Result simlified_derive;
// выведем эту производную
Print<simlified_derive>::name(cout);
cout << endl << "---------------------------------" << endl;
// значение функции в точке
cout << "F'(0.5) = " << Value<simlified_derive>::get(0.5) << endl;
return 0;
}
Собственно сам код.
Functions.h — описание функций
#pragma once
namespace cm
{
namespace fun
{
/// константа
template <int N> struct ConstI
{
enum { value = N; };
};
typedef ConstI<0> Zero;
typedef ConstI<1> One;
/// линейная функция - параметр
struct X
{
typedef One derive;
template <class TOut> static void name(TOut & out) { out << "x"; }
static double get(double d) { return d; }
};
/// обратный элемент (-f(x))
template <class Fun> struct Inverse
{
};
/// сумма
template <class Left, class Right> struct Sum
{
};
/// произведение
template <class Left, class Right> struct Multiply
{
};
/// целочисленная степень
template <class Fun, int N> struct PowerI
{
};
/// деление
template <class Numerator, class Denominator> struct Div
{
};
template <class Numerator> struct Div<Numerator, Zero>;
/// синус
template <class Fun> struct Sin
{
};
/// косинус
template <class Fun> struct Cos
{
};
};
namespace do_fun
{
/// применение N раз к функции Fun правила TAction
template <int N, class Fun, template <class> class TAction> struct ApplyNTimes
{
typedef typename ApplyNTimes<N-1, typename TAction<Fun>::Result, TAction>::Result Result;
};
template <class Fun, template <class> class TAction> struct ApplyNTimes<0, Fun, TAction>
{
typedef Fun Result;
};
};
};
PrintFunctions.h — вывод функции на экран
#pragma once
#include "Functions.h"
namespace cm
{
namespace do_fun
{
using namespace fun;
template <class TOut> void print_header(TOut & out) { out << "("; }
template <class TOut> void print_footer(TOut & out) { out << ")"; }
template <class Fun> struct Print
{
template <class TOut> static void name(TOut & out) { Fun::name(out); }
};
template <int N> struct Print<ConstI<N> >
{
template <class TOut> static void name(TOut & out) { out << N; }
};
template <class Fun> struct Print<Inverse<Fun> >
{
template <class TOut> static void name(TOut & out)
{
print_header(out);
out << "-";
Print<Fun>::name(out);
print_footer(out);
}
};
template <class Left, class Right> struct Print<Sum<Left, Right> >
{
template <class TOut> static void name(TOut & out)
{
print_header(out);
Print<Left>::name(out);
out << " + ";
Print<Right>::name(out);
print_footer(out);
}
};
template <class Left, class Right> struct Print<Multiply<Left, Right> >
{
template <class TOut> static void name(TOut & out)
{
print_header(out);
Print<Left>::name(out);
out << " * ";
Print<Right>::name(out);
print_footer(out);
}
};
template <class Fun, int N> struct Print<PowerI<Fun, N> >
{
template <class TOut> static void name(TOut & out)
{
print_header(out);
Print<Fun>::name(out);
out << "^" << N;
print_footer(out);
}
};
template <class Numerator, class Denominator> struct Print<Div<Numerator, Denominator> >
{
template <class TOut> static void name(TOut & out)
{
print_header(out);
Print<Numerator>::name(out);
out << " / ";
Print<Denominator>::name(out);
print_footer(out);
}
};
template <class Fun> struct Print<Sin<Fun> >
{
template <class TOut> static void name(TOut & out)
{
out << "sin(";
Print<Fun>::name(out);
out << ")";
}
};
template <class Fun> struct Print<Cos<Fun> >
{
template <class TOut> static void name(TOut & out)
{
out << "cos(";
Print<Fun>::name(out);
out << ")";
}
};
};
};
DeriveFunction.h — нахождение производной функции
#pragma once
#include "Functions.h"
namespace cm
{
namespace do_fun
{
using namespace fun;
template <class Fun> struct Derive
{
typedef typename Fun::derive Result;
};
/// производная константы
template <int N> struct Derive<ConstI<N> >
{
typedef Zero Result;
};
/// производная обратного элемента
template <class Fun> struct Derive<Inverse<Fun> >
{
typedef Inverse<typename Derive<Fun>::Result> Result;
};
/// производная суммы
template <class Left, class Right> struct Derive<Sum<Left, Right> >
{
typedef Sum<typename Derive<Left>::Result, typename Derive<Right>::Result> Result;
};
/// производная произведения
template <class Left, class Right> struct Derive<Multiply<Left, Right> >
{
typedef Sum < Multiply<typename Derive<Left>::Result, Right>,
Multiply<Left, typename Derive<Right>::Result>
> Result;
};
/// производная целочисленной степени
template <class Fun, int N> struct Derive<PowerI<Fun, N> >
{
typedef Multiply<ConstI<N>, Multiply<PowerI<Fun, N-1>, typename Derive<Fun>::Result> > Result;
};
template <class Fun> struct Derive<PowerI<Fun, 1> >
{
typedef typename Derive<Fun>::Result Result;
};
/// производная деления
template <class Numerator, class Denominator> struct Derive<Div<Numerator, Denominator> >
{
typedef Div < Sum < Multiply<typename Derive<Numerator>::Result, Denominator>,
Inverse<Multiply<Numerator, typename Derive<Denominator>::Result> >
>,
PowerI<Denominator, 2>
> Result;
};
/// производная синуса
template <class Fun> struct Derive<Sin<Fun> >
{
typedef typename Multiply<Cos<Fun>, typename Derive<Fun>::Result> Result;
};
/// производная косинуса
template <class Fun> struct Derive<Cos<Fun> >
{
typedef typename Multiply<Inverse<Sin<Fun> >, typename Derive<Fun>::Result> Result;
};
};
};
ValueFunction.h — нахождение значения функции в точке
#pragma once
#include <cmath>
#include "Functions.h"
namespace cm
{
namespace do_fun
{
using namespace fun;
template <class Fun> struct Value
{
static double get(double x) { return Fun::get(x); }
};
/// значение константы
template <int N> struct Value<ConstI<N> >
{
static double get(double x) { return N; }
};
/// значение обратного элемента
template <class Fun> struct Value<Inverse<Fun> >
{
static double get(double x) { return -Value<Fun>::get(x); }
};
/// значение суммы
template <class Left, class Right> struct Value<Sum<Left, Right> >
{
static double get(double x) { return (Value<Left>::get(x) + Value<Right>::get(x)); }
};
/// значение произведения
template <class Left, class Right> struct Value<Multiply<Left, Right> >
{
static double get(double x) { return (Value<Left>::get(x) * Value<Right>::get(x)); }
};
/// значение целочисленной степени
template <class Fun, int N> struct Value<PowerI<Fun, N> >
{
static double get(double x) { return (Value<Fun>::get(x)*Value<PowerI<Fun, N-1> >::get(x)); }
};
template <class Fun> struct Value<PowerI<Fun, 1> >
{
static double get(double x) { return Value<Fun>::get(x); }
};
/// значение деления
template <class Numerator, class Denominator> struct Value<Div<Numerator, Denominator> >
{
static double get(double x) { return (Value<Numerator>::get(x) / Value<Denominator>::get(x)); }
};
/// значение синуса
template <class Fun> struct Value<Sin<Fun> >
{
static double get(double x) { return std::sin(Value<Fun>::get(x)); }
};
/// значение косинуса
template <class Fun> struct Value<Cos<Fun> >
{
static double get(double x) { return std::cos(Value<Fun>::get(x)); }
};
};
};
SimplifyFunction.h — операции упрощения функции
#pragma once
#include "Functions.h"
namespace cm
{
namespace do_fun
{
using namespace fun;
template <class Fun> struct Simplify
{
typedef Fun Result;
};
/// упрощение инверсии
template <int N> struct Simplify<Inverse<ConstI<N> > >
{
typedef ConstI<-N> Result;
};
template <class Fun> struct Simplify<Inverse<Inverse<Fun> > >
{
typedef typename Simplify<Fun>::Result Result;
};
/// упрощение суммы
template <class Left, class Right> struct Simplify<Sum<Left, Right> >
{
typedef Sum<typename Simplify<Left>::Result, typename Simplify<Right>::Result> Result;
};
template <class Right> struct Simplify<Sum<Zero, Right> >
{
typedef typename Simplify<Right>::Result Result;
};
template <class Left> struct Simplify<Sum<Left, Zero> >
{
typedef typename Simplify<Left>::Result Result;
};
template <class Fun> struct Simplify<Sum<Fun, Inverse<Fun> > >
{
typedef Zero Result;
};
template <class Fun> struct Simplify<Sum<Inverse<Fun>, Fun> >
{
typedef Zero Result;
};
template <int N1, int N2> struct Simplify<Sum<ConstI<N1>, ConstI<N2> > >
{
typedef ConstI<N1 + N2> Result;
};
/// упрощение произведения
template <class Left, class Right> struct Simplify<Multiply<Left, Right> >
{
typedef Multiply<typename Simplify<Left>::Result, typename Simplify<Right>::Result> Result;
};
template <class Right> struct Simplify<Multiply<Zero, Right> >
{
typedef Zero Result;
};
template <class Left> struct Simplify<Multiply<Left, Zero> >
{
typedef Zero Result;
};
template <class Right> struct Simplify<Multiply<One, Right> >
{
typedef typename Simplify<Right>::Result Result;
};
template <class Left> struct Simplify<Multiply<Left, One> >
{
typedef typename Simplify<Left>::Result Result;
};
template <int N1, int N2> struct Simplify<Multiply<ConstI<N1>, ConstI<N2> > >
{
typedef ConstI<N1 * N2> Result;
};
/// упрощение целочисленной степени
template <class Fun, int N> struct Simplify<PowerI<Fun, N> >
{
typedef PowerI<typename Simplify<Fun>::Result, N> Result;
};
/// упрощение деления
template <class Numerator, class Denominator> struct Simplify<Div<Numerator, Denominator> >
{
typedef Div<typename Simplify<Numerator>::Result, typename Simplify<Denominator>::Result> Result;
};
template <class Denominator> struct Simplify<Div<Zero, Denominator> >
{
typedef Zero Result;
};
template <class Numerator> struct Simplify<Div<Numerator, One> >
{
typedef typename Simplify<Numerator>::Result Result;
};
/// упрощение синуса
template <class Fun> struct Simplify<Sin<Fun> >
{
typedef Sin<typename Simplify<Fun>::Result> Result;
};
template <> struct Simplify<Sin<Zero> >
{
typedef Zero Result;
};
/// упрощение косинуса
template <class Fun> struct Simplify<Cos<Fun> >
{
typedef Cos<typename Simplify<Fun>::Result> Result;
};
template <> struct Simplify<Cos<Zero> >
{
typedef One Result;
};
};
};
... << RSDN@Home 1.1.4 beta 2 >>