模板化功能设计的可扩展性

时间:2013-05-11 23:40:58

标签: c++ c++11

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

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

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){ ... };

对于光线/ shpehre交叉点,我们将提供以下实现:

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

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

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

/** 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时问题会以某种方式减少。这就是我不喜欢的。

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

也许模板不适合这个,我可以为每个案例提供不同的功能......

谢谢。

1 个答案:

答案 0 :(得分: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 );
    

    对返回值进行切片。即使它不是virtual,也会调用正确的析构函数。但如果您愿意,可以使用virtual

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

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

    这很好,因为用户需要知道返回类型,才能使用该功能。

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

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