3

我正在实现 5 个坐标系(我们称它们为 A、B、C、D、E),每个坐标系都有自己独特的类型Coordinates<System>来保存坐标。我希望 C++ 编译器能够在不同系统的坐标之间自动正确转换。坐标变换形成一个图形:ABCD 和 CE。因此,我们只需要指定 8 个基本转换,编译器将生成其余的:

enum CoordSys { A,B,C,D,E };
template<CoordSys System> struct Coordinates;
template<> struct Coordinates<A> {  // specialisation for system A
   // ...
   operator Coordinates<B>() const; // implements transformation A -> B
};
template<> struct Coordinates<B> {  // specialisation for system B
   // ...
   operator Coordinates<A>() const; // implements transformation B -> A
   operator Coordinates<C>() const; // implements transformation B -> C
};
template<> struct Coordinates<C> {  // specialisation for system C
   // ...
   operator Coordinates<B>() const; // implements transformation C -> B
   operator Coordinates<D>() const; // implements transformation C -> D
   operator Coordinates<E>() const; // implements transformation C -> E
};
template<> struct Coordinates<D> {  // specialisation for system D
   // ...
   operator Coordinates<C>() const; // implements transformation D -> C
};
template<> struct Coordinates<E> {  // specialisation for system E
   // ...
   operator Coordinates<C>() const; // implements transformation E -> C
};

编译器会计算出任意两个系统坐标之间的转换,例如

double radiusE(Coordinates<E> const&x); // radius is best computed from system E

template<CoordSys Sys> double radius(Coordinates<Sys> const&x)
{ return radiusE(x); }       // implicit type conversion to system E

然而,专业化是乏味的,因为这些// ...部分可能很长而且大致相同(如果我从一个共同的基础继承仍然很乏味)。理想情况下,我想避免专业化并且只定义一个类模板Coordinates<>——我该怎么做?或者还有其他有用的选择吗?

4

3 回答 3

2

我会在构造函数中进行隐式转换,而不是转换为成员函数。

这样,您可以在坐标类型上使用模板构造函数,如果您不需要全速转换,则可以将所有内容转换为笛卡尔(或其他),然后转换为特殊表示:

 template<class X>
 class Coordinate {
     template <class Y>
     Coordinate(Coordinate<Y> that) { setFromCartesian(that.toCartesian()); }

     Coordinate<Cartesian> toCartesian() { ... }

     ....
 }

然后,您可以将该 ctor 专门用于那些需要专用代码速度的转换,但为大多数其他代码保留上述版本。

您还可以使用 enable_if 和 free 函数来确保构造函数正确失败:

   Coordinate<A> convert(Coordinate<B> that) { return ... }       

   template<class X, class Y>
   struct ConvertCheck {
        static const bool ok = False;
   };

   template<>
   struct ConvertCheck<A, B> {
        static const bool ok = True
   };

   ..

   template<class X>
   class Coordinate {  
         typedef Coordinate<X> this_type;

         template <class Y>
         Coordinate(Coordinate<Y> that, boost::enable_if(ConvertCheck<X,Y>::ok) { 
             *this = convert<this_type>(that);
         }

         ...
   }

另一种方法是使用元编程定义转换链并调用正确的序列(使用 boost::mpl 或类似的东西)。那将是一个很好的练习,我现在没有时间充实......

于 2012-04-18T10:54:59.803 回答
2

你如何选择一个简单的Coordinate类型,它具有一些可转换为所有系统的内部表示(例如,它将数据存储在 system 中A),然后有一些方法可以转换为专门的类型?就像是

class Coordinate {
public:
  CoordinateA toSystemA();
  CoordinateB toSystemB();
  // ..
};

我什至不确定你为什么首先需要模板。这个想法是,您有一个可以转换为特化的规范表示,而不是链接转换(假设您想为每个坐标系使用专门的类型,以便您的函数签名更具描述性)。

于 2012-04-18T10:11:15.177 回答
1

既然你说它基本相同,我的想法如下:

enum CoordSys { A,B,C,D,E };

template<CoordSys System>
struct Coordinates
{
    template<CoordSys XformSystem>
    operator Coordinates<typename
                         std::enable_if<!std::is_same<System, XformSystem>::value,
                                        XformSystem>::type
                        >() const
    {
        // implementation according to System -> XformSystem
    }
};

未经测试的想法,请随时编辑。

于 2012-04-18T10:40:52.480 回答