设计一个可以转换为其他库或从其他库转换的类

时间:2013-08-07 00:47:59

标签: c++

我写了一个小的自包含库(仅依赖于C ++标准库),它有自己的内置3D矢量类:

namespace mylibrary {

    struct Vector {
        double x, y, z;

        // and constructors
        // like:
        Vector(double x, double y, double z);

        // and operators
    };

}

它应该与生成/使用3D矢量的其他代码进行交互。

现在,假设一些其他库,其中包含:

namespace otherlibrary {
    struct Vector3 {

        // some different definition

        // And is still able to construct from 3 values
        Vector3(double x, double y, double z);
    };

    doSomething(const Vector3& point); // do something with the point
}

这个其他库可以是3D建模工具或3D引擎的插件API。它还具有3D矢量的概念,但它当然是与我的库的矢量不同的类型,即使语义相同。想想Python的鸭子类型:只要行为符合预期的方式,类型就无关紧要了。

问题:

我可以使用哪种机制方便地将我的库Vector用作otherlibrary::doSomething()的参数?

也就是说,能够写下这个:

otherlibrary::doSomething( mylibrary::Vector(...) );

我当然可以构建我的Vector类,使其具有模板化构造函数,该构造函数接受具有“x,y,z”成员或operator[]的任何类型的T,因此它几乎可以消耗所有任何类型感觉被解释为3D矢量。是否有可能以相反的方式做到这一点?

编辑:

当然,我可以让它依赖于另一个库,然后我可以重用其他库的3D矢量抽象。这是不合理的,因为我的库是通用的,所以对我的向量使用Eigen :: Vector3d是没有意义的,因为它可以在不使用Eigen的环境中使用。

最佳答案:

根据Neil Kirk的回答:

struct Vector {
    using value_type = double;

    template<class T,
             class = typename enable_if<
                 is_constructible<T, value_type,value_type,value_type>::value
                 >::type>
    operator T() const
    {
        return T{x, y, z};
    }
};

当多个重载函数和运算符可用时,enable_if i用于解决歧义; Eigen是需要它的一个实际案例。

2 个答案:

答案 0 :(得分:2)

是将转化运算符添加到Vector类。

operator otherlibrary::Vector3() const
{
    return otherlibrary::Vector3(x, y, z);
}

但这意味着你的矢量现在将依赖于另一个库..

为了避免依赖,没有办法完全按照你的要求去做。替代建议是一个转换函数,如下所示,它对矢量类型做了几个假设。

template<class T, U>
T ConvertVector3(const U& v)
{
    return T(v.x, v.y, v.z);
}

otherlibrary::doSomething(ConvertVector3<otherlibrary::Vector3>(mylibrary::Vector(x, y, z)));

虽然非常冗长:(

实验!!我没有尝试这个,也不知道它是否有效。关注:你的向量可以转换为任何需要3个构造函数争论的类,即使它没有意义

template<class T>
operator T() const
{
    return T(x, y, z);
}

答案 1 :(得分:0)

很少有理由定义自己的vector3类型,这是一个严重的缺点。即使您使用模板做一些聪明的事情,它也可能与其他库中类似的“聪明”冲突。

将运算符定义为自由函数,而不是成员,并使用std::array代替。如果您确实必须拥有自己的类,请定义返回标准类型的to_array()函数。任何理智的库都可以从中转换,即使使用array::data()将其视为C数组也是如此。

(Protip:你可以reinterpret_cast一个C风格的数组到std::array &引用并返回,以避免复制数据。)