Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning nullptr iterators, how to cast them

I'm having some trouble solving an issue in my program. So currently each chunk will return an iterator, but the iterator depends on two cases:

the desired element is found in the chunk: return resultIter; the desired element is not found in the chunk: 'return nullptr`

the first case is simple enough and easy to solve, but the second case is where I am running into trouble. Given a template argument InIter, how can I convert a nullptr into the InIter category?

template< typename InIter, ...>
InInter func(...) {
  InIter res = //returns iter to found element if found
    loop(...)  //if so a token will changed to signify a cancelation
  if(token.was_cancelled())
    return res; //easy enough
  return nullptr; //doesn't work
}

which gives me this error:

'nullptr': all return expressions in a lambda must have the same type: previously it was 'test::test_iterator'

it makes sense, I can't suddenly switch up return types in the middle of a lambda function, but I don't know how to solve this. note the code about is a very simplified version of the issue at hand, in it's actual implementation it is inside a lambda and part of a much bigger function call. However this is the only relevant portion

i've also tried:

return InIter(nullptr);

return (InIter)(nullptr);

return NULL;

return InIter(NULL);

...

Of course none of these work. there as to be an easy way to do this I just am not seeing?

like image 532
Syntactic Fructose Avatar asked Dec 09 '22 07:12

Syntactic Fructose


2 Answers

The expected pattern for using iterators, is that if you want to report that you found no match, you would return the iterator that points to the end of your sequence.

So if you called:

InIter res = find_an_iterator_meeting_an_interesting_condition(begin, end);

and it found no match, you would return end. The caller would be responsible for checking that condition.

like image 74
Bill Lynch Avatar answered Dec 11 '22 11:12

Bill Lynch


There are two approaches.

First, the standard approach, is that when working with iterators, you are actually working with a range of iterators (from a begin, to an end).

In that case, failure to find something would consist of returning end.

In some extreme corner cases this isn't the right thing to do (imagine if you ask "where is the right place to insert Y? And the answer isn't "at the end of the sequence" but rather "somewhere completely different")

In that case, something like boost::optional is the right answer -- your function returns an optional<Iterator>. Then you can return a nullopt to mean "no answer is valid", and an iterator if an answer is valid.

There are proposals to bring in an optional to C++ in C++14.

A "poor man's optional" is a std::pair<bool, Iterator>, where you ignore the .second's value if the .first is false. If you have no access to boost, I'd advise reimplementing optional rather than using this technique.

like image 30
Yakk - Adam Nevraumont Avatar answered Dec 11 '22 11:12

Yakk - Adam Nevraumont