Это на самом деле прекрасный пример зла попытки перегрузить возвращаемый тип магическими значениями и просто сомнительный дизайн интерфейса.
Одним из решений, которое я мог бы использовать для устранения неоднозначности (и, следовательно, необходимости "поведения, подобного исключению") в этом примере, является определение правильного типа возврата:
struct stack{
double* pData;
uint32 size;
};
struct popRC{
double value;
uint32 size_before_pop;
};
popRC pop(struct stack* pS){
popRC rc;
rc.size=pS->size;
if(rc.size){
--pS->size;
rc.value=pS->pData[pS->size];
}
return rc;
}
Использование конечно:
popRC rc = pop(&stack);
if(rc.size_before_pop!=0){
....use rc.value
Это происходит ВСЕ время, но в C ++, чтобы избежать таких двусмысленностей, обычно просто возвращается
std::pair<something,bool>
, где bool является индикатором успеха - посмотрите на некоторые из:
std::set<...>::insert
std::map<...>::insert
Либо добавьте к интерфейсу double*
и верните код возврата (n UNOVERLOADED!), Скажем, enum, указывающий на успех.
Конечно, не нужно возвращать размер в структуре popRC
. Это могло быть
enum{FAIL,SUCCESS};
Но так как размер может послужить полезной подсказкой для pop'er, вы также можете использовать его.
Кстати, я от всей души согласен, что интерфейс структуры стека должен иметь
int empty(struct stack* pS){
return (pS->size == 0) ? 1 : 0;
}