То, что вы хотите, невозможно напрямую без существенного изменения вашего дизайна.
Что вы можете сделать, так это принудительно вызывать вызовы обоими, заключив их в один вызов:
??? foo(const F& f) {
return f.isOk() ? f.value() : f.getError();
}
Однако, это просто переносит проблему на выбор типа возвращаемого значения. Вы можете вернуть std::variant
или с некоторыми изменениями в дизайне std::optional
, но что бы вы ни делали, он будет оставлен вызывающей стороне, чтобы проверить, что на самом деле было возвращено.
Не считайте самых глупых пользователей и не пытайтесь защитить их от любой возможной ошибки. Вместо этого предположим, что они читают документацию.
Необходимость проверить, является ли возвращаемое значение допустимым, является довольно распространенным шаблоном: функции, возвращающие указатель, могут возвращать нулевой указатель, функции, возвращающие итератор, могут возвращать итератор end
. Такие случаи хорошо документированы, и ответственный вызывающий абонент проверит правильность возвращаемого значения.
Чтобы получить дополнительное вдохновение, я отсылаю вас к std::optional
, довольно современному дополнению к C ++, которое также сильно зависит от пользователя, чтобы знать, с чем он имеет дело.
PS: Так же, как один контрпример, пользователь может написать такой код, который делает невозможным выполнение желаемой проверки во время компиляции с вашим текущим дизайном:
int n;
std::cin >> n;
auto f = foo();
if(n > 10 && !f.isOk())
return f.getError();
auto v = f.value();