2
\$\begingroup\$

Our C++ professor told us to practise the use of std::function, lambda and pointers to functions. He asked us to:

Write the function std::function<bool(float)> interval(float low, float high). The function should accept two values low and high and should return a function. The function returned will check if it's parameter is inside or outside the interval (low,high) and will return true or false accordingly.

I tackled the problem with this code.

The function declaration:

std::function<bool(float)> interval (float low,float high){
 return [low,high](float f){ return (f > low) && (f < high); };
}

How is it used in the main:

std::function<bool(float)> interval (float low,float high);
bool res = interval(10, 20)(150);
std::cout << res;

And it works. But I am not sure how the solution is elegant, or "best practise".

In particular, this call bool res = interval(10, 20)(150); is what scares me. It is really awful to call it like this. How would you have done the excersize? Do you find my solution clear?

Toby Speight
87.3k14 gold badges104 silver badges322 bronze badges
asked Jun 17, 2020 at 15:42
\$\endgroup\$
3
  • 3
    \$\begingroup\$ "Is it best practice" isn't really a useful question for homework problems. The task is to use the technique. If you had something that you called like interval(10, 20, 150) that would be wrong. \$\endgroup\$ Commented Jun 17, 2020 at 17:04
  • 4
    \$\begingroup\$ On the other hand, it may help you to understand the value of this if you split up the call. For example, you could have auto isLegalSpeed = interval(0, 60); and on another line if isLegalSpeed(currentSpeed) which would be a lot more readable than if interval(0, 60, currentSpeed) \$\endgroup\$ Commented Jun 17, 2020 at 17:13
  • 3
    \$\begingroup\$ Even better, because these lambdas are objects, you can put them in data structures like maps and arrays. For example, you might have something like speedCheck[highway] = interval(50, 70); and speedCheck[city] = interval(10, 30); That allows for very powerful constructions indeed: if you had a list of speed camera readings from a list of roads, you could then test speedCheck[roadType](speed) for each reading instead of the much more verbose if roadType == city {... \$\endgroup\$ Commented Jun 17, 2020 at 17:16

1 Answer 1

1
\$\begingroup\$

This looks like it almost conforms to the spec (I think those tests should be >= and <= given that's an inclusive interval). You might want to consider what happens if a NaN value is passed in - since they are neither less-than nor greater-than actual numbers, we'll return false, which seems reasonable. It's probably not a good idea to create an interval with NaN as start or end of the range, though!

Though it wasn't your choice, I would question the use of float rather than double here (actually, in real code, I'd probably make it a template function so it can work with any type that has a partial ordering).

If you don't like the chained call syntax, you can separate out using a variable, and that's likely to be a more common case than building and immediately using just once as shown in the question:

auto is_valid = interval(10, 20);
for (auto v: values) {
 if (!is_valid(v)) {
 std::cerr << v << " out of range\n";
 }
}
answered Mar 3, 2022 at 10:18
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.