boost源码学习之gemotry2:设计原理

boost源码学习之gemotry2:设计原理,第1张

boost源码学习之gemotry2:设计原理

boost gemotry

2.设计原理

假设你需要一个C++程序计算两点间的距离,你可能会定义一个结构体:

struct mypoint
{
    double x, y;
};

和一个函数,包含这个算法:

double distance(mypoint const& a, mypoint const& b)
{
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
}

非常简单,它是可用的,但不是通用的。对于库来说,它必须进一步设计。上述设计只能用于笛卡尔坐标系中的二维点、结构mypoint(而不是其他结构)。通用库应能够计算距离:

对于任何point类或结构,而不仅仅是此mypoint类型

在两个以上的维度

对于其他坐标系,例如地球上方或球体上

点与线之间或其他几何图形组合之间

以比双精度更高的精度

避免平方根:我们通常不想这样做,因为这是一个相对昂贵的函数,而比较距离则没有必要

在本节和后续章节中,我们将逐步使设计更通用。

2.1使用模板

距离函数可以变成一个模板函数。这很简单,可以计算除mypoint之外的其他点类型之间的距离。我们添加了两个模板参数,允许输入两种不同的点类型。

template 
double distance(P1 const& a, P2 const& b)
{
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return std::sqrt(dx * dx + dy * dy);
}

这个模板版本稍微好一点,但不多。

考虑一个C++类,其中成员变量受到保护…这样的类不允许直接访问x和y成员。所以,这一段很短,我们继续。

2.2使用Traits

我们需要采用一种通用方法,允许任何点类型作为距离函数的输入。我们将使用traits系统添加几个级别的间接寻址,而不是访问x和y成员。然后,该函数变为:

template 
double distance(P1 const& a, P2 const& b)
{
    double dx = get<0>(a) - get<0>(b);
    double dy = get<1>(a) - get<1>(b);
    return std::sqrt(dx * dx + dy * dy);
}

此调整后的距离函数使用一个通用get函数,用维度作为模板参数,以访问点的坐标。这将转到traits系统,定义如下:

namespace traits
{
    template 
    struct access {};
}

然后专门用于mypoint类型,实现一个名为get的静态方法:

namespace traits
{
    template <>
    struct access
    {
        static double get(mypoint const& p)
        {
            return p.x;
        }
    };
    // same for 1: p.y
    ...
}

调用traits::access::get(a)现在返回x坐标。很好,不是吗?对于库中经常使用的函数来说,它太冗长了。我们可以通过添加额外的免费函数来缩短语法:

template 
inline double get(P const& p)
{
    return traits::access::get(p);
}

这使我们能够为任何具有traits::access专门化的点调用get<0>(a),如本段开头的距离算法所示。因此,我们希望使用x()之类的方法来启用类,只要access结构有专门化,并且有一个静态get函数为维度0返回x(),为维度1和y()返回类似的x(),就可以支持这些类。

Traits?
C++ traits技术浅谈

2.3维度不可知论

现在我们可以计算2D中点之间的距离,任何结构或类的点。然而,我们也想要3D。因此,我们必须使其维度不可知。这使我们的距离函数变得复杂。我们可以使用for循环遍历维度,但是for循环有另一种性能,而不是最初直接添加坐标。但是,我们可以更多地使用模板,并使距离算法如下,更复杂,但对模板迷有吸引力:

template 
struct pythagoras
{
    static double apply(P1 const& a, P2 const& b)
    {
        double d = get(a) - get(b);
        return d * d + pythagoras::apply(a, b);
    }
};

template 
struct pythagoras
{
    static double apply(P1 const&, P2 const&)
    {
        return 0;
    }
};

距离函数正在调用pythagoras结构,指定维度数:

template 
double distance(P1 const& a, P2 const& b)
{
    BOOST_STATIC_ASSERT(( dimension::value == dimension::value ));

    return sqrt(pythagoras::value>::apply(a, b));
}

上面提到的dimension,使用traits类定义:

namespace traits
{
    template 
    struct dimension {};
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5702750.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存