std::for_each "iterates" over a range, so to use it with an array of indeterminate length, you need to use custom iterators to signal the end of the array (on NULL member). If you insist on using NULL-terminated char* array, you could of course create your own for_each function for it, for example like this:
template <typename Function>
void for_each_in_null_terminated_cstring_array(const char** array, Function f)
{
while (*array) {
f(*array);
array++;
}
}
const char *names[] = { "Bob", "Adam", "Simon", NULL };
for_each_in_null_terminated_cstring_array(names, func);
I'm not really recommending this solution, though.
edit: Yes, more general is always more better, isn't it?
template <typename T, typename Function>
void for_each_in_null_terminated_array(T* array, Function f)
{
while (*array) {
f(*array);
array++;
}
}
(Here's the implementation of a null terminated ("false"-terminated) iterator I mentioned earlier - with a change or two based on suggestions below. It should be a real InputIterator)
template <class T>
class nt_iterator: public std::iterator<std::input_iterator_tag, T>
{
public:
typedef typename nt_iterator<T>::pointer pointer;
typedef typename nt_iterator<T>::value_type value_type;
nt_iterator(): p(), pte(true) {}
nt_iterator(pointer p_): p(p_), pte(!p_) {}
nt_iterator(const nt_iterator<T>& rhs): p(rhs.p), pte(rhs.pte) {}
nt_iterator<T>& operator++() {
++p;
if (!*p) pte = true; // once past-the-end, always past-the-end
return *this;
}
nt_iterator<T> operator++(int) {
nt_iterator n(*this);
operator++();
return n;
}
bool operator==(const nt_iterator<T>& rhs) {
return pte && rhs.pte || p == rhs.p;
}
bool operator!=(const nt_iterator<T>& rhs) {
return !(operator==(rhs));
}
value_type operator*() { return *p; }
private:
pointer p;
bool pte; // past-the-end flag
};
And how it's used:
void print(const char* str);
int main()
{
const char* array[] = {"One", "Two", "Three", NULL, "Will you see this?"};
std::for_each(nt_iterator<const char*>(array),
nt_iterator<const char*>(),
print);
}
It's probably a bit slower than the loop version, because of the increased amount of equivalence checks - the speed difference is of course insignificant compared to, for example, printing text - but one should note that std::for_each
does not magically make looping faster (in fact, you might be surprised to see how your compiler vendor defines the function - that is, if you are expecting too much).