假设我想编写一个函数,该函数在R ^ 3中采用一个平面和一条线并返回它们的交点。显然,我必须区分三种可能的情况:i)直线与平面在单个点上相交; ii)直线是平面的子集; iii)直线与平面平行(而不是平面的子集) )。这将导致该函数的三种可能的返回类型。
最近我与OCaml进行了大量合作,这使我可以通过从函数中返回变量类型来非常明确地区分这些不同类型。人们如何用C ++处理此类问题?
想到的一个想法是使用{bool,bool,vector}的元组作为我的返回类型,其中第一个布尔值表示线和平面是否具有非空交点,第二个布尔值表示是否如果第一个布尔值是true(否则是无意义的),则它们在单个点处相交;如果两个布尔值都是true(否则是无意义的),则向量将返回唯一的相交。但是,这感觉非常笨拙,我必须使用注释将元组条目含义的功能告知用户该函数,返回可能毫无意义的变量,等等。
解决此问题的最佳方法是什么?
答案 0 :(得分:5)
这里有几种 generic (即不限于几何线和点)来解决该问题。
std::variant
(或者对于无法运行C ++ 17的用户而言,是其较老的兄弟姐妹boost::variant
)。平原旧工会(已标记):
struct LinePlaneIntersection {
enum { IsLine, IsPlane } intersection_type;
union {
Point p;
Line l;
};
};
如果Point
和Line
具有非平凡的构造函数和/或析构函数,则需要在上述方案中添加ctor和dtor。
纯属旧继承。
class LinePlaneIntersection { ... };
class NoIntersection : public LinePlaneIntersection { ... };
class OnePointIntersection : public LinePlaneIntersection { ... };
class OneLineIntersection : public LinePlaneIntersection { ... };
从您的函数中返回LinePlaneIntersection*
(或更好且更可取的std::unique_ptr<LinePlaneIntersection>
)。然后,当然存在如何处理返回值的问题。您可能要在这里使用Visitor pattern。
继续传递。不要返回任何内容,而是接受延续。在这种情况下,将继续执行三个操作:
void intersect (Line line, Plane plane,
std::function<void(Line)> onLine,
std::function<void(Point)> onPoint,
std::function<void()> onNothing);
答案 1 :(得分:4)
我会做类似的事情:
struct Point3D
{
double x;
double y;
double z;
};
struct Line
{
Point3D p1;
Point3D p2;
};
struct Plan {
Point3D p;
Point3D orthogonalDir;
};
std::optional<std::variant<Point3D, Line>>
ComputeIntersection(const Line& line, const Plan& plan);
答案 2 :(得分:1)
为什么不返回带有枚举类型的结构?然后,使用该功能的人可以先检查交叉点的类型,然后再尝试使用数据。
enum IntersectType {
INTERSECTION_NONE,
INTERSECTION_POINT,
INTERSECTION_LINE,
};
struct Point3D {
double x;
double y;
double z;
}
struct LinePlaneIntersect {
IntersectType type;
std::vector<Point3D> intersect; //since you mentioned vector
};
//Check within another function
struct LinePlaneIntersect intersection = fun(line, plane);
if (intersection.type == INTERSECTION_POINT) {
// do something
}
答案 3 :(得分:1)
尽管有许多不错的新方法可以处理此问题(std::tuple
,std::variant
等),但经过实践检验的方法是设计一个class
(甚至一组相关的类),可以表示各种状态并返回该状态的一个实例。
随着项目的发展,这种方法似乎总是最好地扩展。如此之多,以至于Java背后的委员会从未向其语言和库中发出元组或变体类型。