具有不同返回类型的C++函数

C++ function with different return types

本文关键字:C++ 函数 返回类型      更新时间:2023-10-16

假设我想写一个函数,它取R^3中的一个平面和一条线,并返回它们的交集。显然,我必须区分三种可能的情况:I(直线与平面在一个点相交,ii(直线是平面的子集,iii(直线平行于平面(而不是平面的子集(。这导致函数有三种可能的返回类型。

我最近一直在使用OCaml,这将使我能够通过从函数中返回一个变体类型来非常明确地区分这些不同的类型。在C++中,人们是如何处理这类问题的?

脑海中浮现的一个想法是使用{bool,bool,vector}的元组作为我的返回类型,其中第一个布尔值表示直线和平面是否有非空相交,第二个布尔值则表示如果第一个布尔为真,它们是否在一个点相交(否则毫无意义(,如果两个布尔值都为真(否则就没有意义(,则向量返回唯一的交集。然而,这感觉非常不雅和笨拙,我必须使用注释通知用户元组条目的含义,我返回可能没有意义的变量,等等。

处理这个问题的最佳方法是什么?

这里有几种通用(即不限于几何线和点(方法来处理这个问题。

  1. std::variant(对于那些不能运行C++17的人来说,是它的老兄弟boost::variant(
  2. 普通旧工会(已标记(:

    struct LinePlaneIntersection {
    enum { IsLine, IsPlane } intersection_type;
    union {
    Point p;
    Line l;
    };
    };
    

    如果PointLine具有非平凡的构造函数和/或析构函数,则需要将actor和dtor添加到上述方案中。

  3. 朴素的古老遗产。

    class LinePlaneIntersection { ... };
    class NoIntersection : public LinePlaneIntersection { ... };
    class OnePointIntersection : public LinePlaneIntersection { ... };
    class OneLineIntersection : public LinePlaneIntersection { ... };
    

    从函数中返回一个LinePlaneIntersection*(或更好、更可取的std::unique_ptr<LinePlaneIntersection>(。当然,还有一个问题是如何处理返回的值。您可能需要在此处使用访问者模式。

  4. 继续通过。不要返回任何内容,而是接受继续。在这种情况下,有三个延续:

    void intersect (Line line, Plane plane,
    std::function<void(Line)> onLine,
    std::function<void(Point)> onPoint,
    std::function<void()> onNothing);
    

我会做一些类似的事情:

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);

尽管有很好的新方法来处理这一问题(std::tuplestd::variant和c.(,但久经考验的方法是设计一个class(甚至一组相关类(,它可以表示各种状态并返回其实例。

随着项目的发展,这种方法似乎总是能最好地扩展。如此之多,以至于Java背后的委员会从未向他们的语言和库中发出元组或变体类型。

为什么不返回具有枚举类型的结构?使用该功能的人可以在尝试使用数据之前先检查交叉口的类型。

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
}