递归模板定义

Recursive template definition

本文关键字:定义 递归      更新时间:2023-10-16

我有一个递归模板定义(我刚刚创建了这个术语)。我认为代码可以更好地解释它。

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类中的实现给我带来了问题。我知道模板类是在编译之前定义的,但在预处理之后。因此,我不知道如何将此功能发挥作用。每个具有模板参数n的NthOrderFunction都需要具有模板参数n-1的NthOrderFunction。你可以看出这是一个问题。问题是,即使n在使用中永远不会是负数,无论我做多少编码,都会说服"模板定义引擎"不要为n<1.

有人对此有意见吗?你想出了什么解决方案?

这与模板元编程101示例-阶乘相同,只是内容稍微复杂一些。

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

而且你需要同样的解决方案——对基本情况进行专门化。

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

你的是部分的,而不是全部的,但它仍然有效。

添加类似以下内容:

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"扩展到运行时代码(永远不会执行)。这段代码用不存在的情况替换了可以编译的情况,因此没有无限递归的选项。