Sometimes the result of a function can not be represented by a single return value. For example: A function that intersects two lines. One might want the function to return both the actual point of intersection as well as their relation to each other (that is parallel, identical, intersecting or skewed).
Let us assume this example where the point of intersection is represented by some sort of class and the lines positional relation by an integer holding a specified value for each of the 4 possibilities:
int IntersectLines(Line l1, Line l2, Point& point);
Point point{};
int result = IntersectLines(l1, l2, point);
That is how I would have implemented it to this day but now I am wondering whether it is possible to have a similar implementation but with a consteval function. Line
and Point
have constexpr constructors and everything and the calculation itself can be compile time evaluated as well. The only problem is that I can't think of a way to have two return values. I already thought of std::pair
but a solution more similar to passing a reference would be prefered. If such a solution doesn't exist I will have to fall back to std::pair
.
It doesn't work by passing point
by reference (Point& point
) because "the expression did not evaluate to a constant" but passing by const reference (const Point& point
) won't work either because I wouldn't be able to assign the result to point
. Is there a way to get this working?
CodePudding user response:
You can return a std::pair<Point, Relationship>
.
Example:
consteval std::pair<Point, Relationship> IntersectLines(const Line& l1, const Line& l2)
{
// replace with the real calc below, this is just for show:
const Point pnt{l1.p1.x l2.p1.x, l1.p1.y l2.p1.y};
const Relationship rel = Relationship::parallel;
return {pnt, rel};
}
And call it like so:
int main() {
constexpr Line l1({1,2}, {3,4}), l2({5,6}, {7,8});
constexpr auto pr = IntersectLines(l1, l2);
auto&[pnt, rel] = pr;
return pnt.x pnt.y; // 14
}
With optimization, the resulting assembly is likely to become something like
main:
mov eax, 14
ret
CodePudding user response:
You cannot pass a reference to a consteval
function and have the function modify the target of the reference, except if you do so in inside another consteval
function.
The call to a consteval
function must be on its own a constant expression, assuming it is not called inside another consteval
function.
However, a constant expression cannot modify an object outside of the evaluation of the constant expression itself.
In both a consteval
and usual function, you can however return a std::pair
or std::tuple
of multiple return values and e.g. retrieve them at the call site as a structured binding.