Skip to content

← Errors step 1 of 4

Easy Primitives

Zero is an answer

An average can be zero. It can also be negative. Returning 0 or -1 to mean "no average" makes that case indistinguishable from a valid result. A special value used this way is called a sentinel. It works only when the function's contract reserves it and excludes it from valid results.

std::optional<int> represents the two cases separately: an integer result, or no result. An optional that contains a value is also called engaged.

std::optional<int> result = 0;       // contains zero
std::optional<int> missing = std::nullopt;  // contains no value

Checking and reading an optional

Operation Meaning
o.has_value() or if (o) Check whether a value is present
*o or o->field Access the value; it must be present
o.value() Access the value, or throw std::bad_optional_access
o.value_or(fallback) Return the value, or the fallback if absent

The compiler does not require a check before *o or o->field. In C++20, accessing an empty optional this way is undefined behaviour. Check first, or use value() when an exception is the intended response. Use value_or when a default makes sense for the caller.

An optional<int> stores its integer inside the optional object without a separate heap allocation. For other value types, such as std::string, the contained object may still allocate its own storage.

Choosing how to represent absence

Optional records whether a value exists; it does not explain why it is absent. It can represent a failed operation when the caller needs only that distinction. If the caller needs an error reason, use a result type that includes one, such as std::expected<T, E> in C++23.

C++20 does not support std::optional<T&>. A non-owning pointer is one option for referring to an object that may be absent: nullptr means no object, and any non-null pointer must still refer to a valid object when used.

Your task

std::optional<int> average(const std::vector<int>& values, int lo, int hi);

Average only values in the inclusive range [lo, hi]. Return their integer average, with division truncated toward zero. Return an empty optional when no values qualify. The test inputs keep the count and running sum within the range of int.

Values Range Result
[-2, 2] [-5, 5] A value of 0
[99] [-5, 5] No value
[-3, -4] [-10, 0] A value of -3

The starter returns an optional containing zero when no values qualify. Fix that return while keeping the guard before division.

Leave the provided summarize function unchanged. It calls average for each group and encodes an absent result as -1000 for the test output. That encoding is a test convention; average itself must return absence with std::nullopt, so callers can distinguish it from every integer.