Определение рекурсивного шаблона - PullRequest
6 голосов
/ 16 июня 2011

У меня есть рекурсивное определение шаблона (я только что придумал этот термин). Я думаю, что код объясняет это лучше.

template<typename X>
class Domain
{
    public:
        X begin;
        X end;

        Domain(
            X _begin, 
            X _end)
            : begin(_begin)
            , end(_end)
        {
            // ...
        }

        bool Contains(
           const X& t) const
        {
            // ...
        }
};

template<typename X, typename Y>
class IFunction
{
    public:
        Domain<X> myDomain;

    public:
        IFunction(
            const Domain<X>& dom)
            : myDomain(dom)
        {

        }

        virtual Y
        Calc(
            const X& IV) const = 0;

        virtual IFunction<X, Y>*
        GetDerivative() const = 0;
};

template<typename X, typename Y, int n>
class NthOrderFunction
    : public IFunction<X, Y>
{
    public:
        double coeffs[n+1];

    public:
        NthOrderFunction(
            const Domain<X>& dom,
            ... )
            : IFunction(dom)
        {

        }

        virtual Y
        Calc(
            const X& IV) const
        {
            // temporary compile solution
            return Y();
        }

        virtual IFunction<X, Y>*
        GetDerivative() const
        {
            if ( n > 1 )
            {
                return new NthOrderFunction<X, Y, n-1>(dom, ...);
            }
            return new FlatLine<X, Y>(dom);
        }
};

Я взял много наследства и других отношений, чтобы он был читабельным, простым и загадочным. Таким образом, новая опечатка могла появиться при редактировании кода, но, пожалуйста, игнорируйте ее. Код работал хорошо в течение многих лет, единственная проблема, которую я имею, это та, которую я собираюсь указать.

Недавно я добавил функцию "GetDerivative", и ее реализация в классе NthOrderFunction вызывает у меня проблемы. Я знаю, что шаблоны классов определены до компиляции, но после предварительной обработки. Поэтому я не понимаю, как заставить эту функциональность когда-либо работать. Для каждой функции NthOrderFunction с параметром шаблона n требуется функция NthOrderFunction с параметром шаблона n-1. Вы можете видеть, что это проблема. Дело в том, что, хотя n никогда не будет отрицательным при использовании, никакое количество кодирования, которое я делаю, убедит «механизм определения шаблона» не беспокоиться о случаях n <1; </p>

у кого-нибудь когда-нибудь были проблемы с этим? И какие решения вы придумали?

Ответы [ 2 ]

7 голосов
/ 16 июня 2011

Это то же самое, что и шаблон метапрограммирования 101 в качестве примера - факториал, только содержание несколько сложнее.

template<int N> struct factorial { enum { value = N * factorial<N-1>::value }; };

И вам нужно то же решение - специализация для базового варианта.

template<> struct factorial<1> { enum { value = 1 }; };

Ваш будет частичным, а не полным, но все равно будет работать.

2 голосов
/ 16 июня 2011

Добавьте что-то вроде:

template<typename X, typename Y>
class NthOrderFunction<X, Y, 1>
    : public IFunction<X, Y>
{
    public:
        double coeffs[n+1];

    public:
        NthOrderFunction(
            const Domain<X>& dom,
            ... )
            : IFunction(dom)
        {

        }

        virtual Y
        Calc(
            const X& IV) const
        {
            // temporary compile solution
            return Y();
        }

        virtual IFunction<X, Y>*
        GetDerivative() const
        {
            return new FlatLine<X, Y>(dom);
        }
};

и удалите случай n == 1. из своего случая рекурсии.

В качестве совета, найдите книгу или учебное пособие или подобное по метапрограммированию шаблонов.Одним из базовых методов является использование рекурсии в шаблонах таким способом.Строго говоря, это еще не метапрограммирование, это просто рекурсивные шаблоны.Книга / учебное пособие объяснят, как работают более продвинутые приемы, которые вы можете использовать для своей выгоды при расширении этого.

Причина, по которой это работает, заключается в том, что оригинал все равно расширит время компиляции "if" до кода времени выполнения(это никогда не будет выполнено).Этот код заменяет один случай, когда он может быть скомпилирован, на тот, где его нет, поэтому нет возможности бесконечной рекурсии.

...