C++ function with different return types

  • A+

Let's say I want to write a function that takes a plane and a line in R^3 and returns their intersection. Obviously, I have to distinguish between three possible cases: i) the line intersects the plane in a single point, ii) the line is a subset of the plane, iii) the line is parallel to the plane (and not a subset of it). This results in three possible return types for the function.

I've been working a lot with OCaml recently, which would allow me to distinguish between these different types very explicitly by returning a variant type from my function. How do people deal with this kind of issue in C++?

One idea that comes to mind is to use a tuple of {bool, bool, vector} as my return type, where the first boolean says whether the line and the plane have a non-empty intersection, the second boolean says whether they intersect in a single point if the first boolean is true (and is meaningless otherwise), and the vector returns the unique intersection if both booleans are true (and is meaningless otherwise). However, this feels very inelegant and hacky, I have to inform users of the function of the meaning of the tuple entries using comments, I return variables which can be meaningless, etc.

What is the best way to deal with this problem?


Here are several generic (i.e. not limited to geometrical lines and points) ways to cope with the problem.

  1. std::variant (or its older sibling boost::variant for those who cannot run C++17).
  2. Plain old union (tagged):

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

    If Point and Line have not-trivial constructors and/or destructors, you'd need to add ctors and dtors to the above scheme.

  3. Plain old inheritance.

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

    Return a LinePlaneIntersection* (or better and much preferable std::unique_ptr<LinePlaneIntersection>) from your function. Then there's of course the problem of what to do with the returned value. You may want to use the Visitor pattern here.

  4. Continuation passing. Don't return anything, accept a continuation instead. In this case, three continuations:

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


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: