2

抱歉标题,我找不到更合适的名字。如果有人有更好的,我很乐意改变它。

假设我们有一组实体几何对象:

struct ray { ... };
struct plane { ... };
struct box { .... };
struct sphere { .... };

我目前正在考虑交叉算法的模板函数,以便我们可以根据运行时检查的类型创建函数的专用版本:

template <typename operand_type1, 
          typename operand_type2> 
          RET_DATA check_intersection(operand_type1 operand1, operand_type2 operand2){ ... };

对于 ray/shpehre 相交,我们将提供以下实现:

template<> RET_DATA check_intersection<ray, sphere>(ray operand1, sphere operand2){ ... };

我故意未定义 RET_DATA,因为根据每个专业化,我们可能希望返回不同的信息。例如对于这种情况,我们可以返回交叉点的数量(如果有的话)和相关的点。对于球体-球体,我们可以返回相交的体积。问题是我们还需要创建这个模板的用户需要知道的新(返回)类型。

我目前最好的候选想法是创建一个仿函数并专门针对每种类型。在仿函数内部定义一个返回结构,每个特化都有一个通用名称(即result):

/** templated functor */
template<typename T1, typename T2> struct check_intersect {
    typedef intersection_data<T1, T2> result;

    check_intersect(T1 operand1, T2 operand2) : operand1(operand1), operand2(operand2) {}

    result operator()(T1 operand1, T2 operand2){ ... }  
};

/** tempalted auxiliar return data type */
template<typename T1, typename T2> struct intersection_data { ... }

然后,我们将根据数据类型为两者提供专业化。这或多或少地以这种使用模式结束:

 check_intersect<ray, sphere>::result ret = check_intersect<ray, sphere>(my_ray, my_sphere);

尽管使用现代 IDE,问题以某种方式减少了,但用户仍然必须猜测界面的结果。这是我不喜欢的地方。

这种方法有缺陷吗?有没有更好的设计理念来解决即将推出的实体几何类型的可扩展性?这是最优雅的方法吗?

也许模板不是正确的工具,我可以为每种情况提供不同的功能......

谢谢你。

4

1 回答 1

2
  1. 除非有一般情况的实现,否则不要使用模板。除非你实际上有一个函数体template< typename x, typename y > check_intersection( x, y ),否则不要声明它。

  2. 使用重载而不是模板特化。重载就是为解决这类问题而设计的工具。专业不一样。可以将特定的重载与通用模板一起使用。

  3. 为不同的 RET_DATA 类型使用基类。virtual如果绑定到常量引用,则不需要析构函数:

    check_intersect_result const &sect = check_intersect( my_sphere, my_cone );
    

    这不会返回值进行切片。即使不是,也会调用正确的析构函数virtualvirtual但如果你喜欢,你可以使用。

    如果您使用 C++11 ,问题就会完全消失auto。那么你甚至不需要基类。

    auto &&sect = check_intersect( my_sphere, my_cone );
    

    这很好,因为用户不需要知道返回类型就可以使用该函数。

  4. 单独的普通函数和元函数比具有成员operator()和的伞类更好result_type。对于可扩展性,添加新的自由函数和元函数特化比修改单体类更容易。

  5. intersection_result制作一个元函数可能不是一个坏主意,例如intersection_result< sphere, cone >::type,但我会避免要求它只是调用该函数。

于 2013-05-12T02:47:34.150 回答