Работа с функциями в compile-time
От: VNG Беларусь https://organicmaps.app/
Дата: 23.03.05 16:05
Оценка: 38 (3)
Вот вчера после принятия "расширителя сознания" наваял такое.
Захотелось поиметь работу хотя-бы с базовыми функциями в 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 >>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.