I've been using both C++11 and Python lately. While the new C++11 features add a lot of value, I still find it frustratingly verbose for some things. For example, finding an element in a collection:
std::string type = "foo";
auto it = std::find_if(
channel_widgets.begin(),
channel_widgets.end(),
[type](const std::shared_ptr<Widget> &w){
return (w->getType() == type);
}
);
if (it == channel_widgets.end()) {
std::cerr << "widget not found" << std::endl;
} else {
std::shared_ptr<Widget> target_widget = *it;
std::cout << "widget found." << std::endl;
}
versus (for example):
type = "foo"
matches = [x for x in widgets if x.get_type() == type];
if matches:
target_widget = matches[0]
print "widget found:",target_widget
else:
print "widget not found"
I may be missing out on some C++11 feature for doing this better. (Or even some Python feature for doing this better!)
"I may be missing out on some C++11 for doing this better"
First write a function that searches an entire range with a predicate, so you don't have to write the .begin() and .end() anymore. That's just applying DRY. Then you could write a helper struct that wraps an iterator and the end iterator of the range searched, so you can give it an operator bool (). Return this struct from your find function and you get code like this:
auto result = my::find_if( channel_widgets, predicate );
if( result )
do_stuf_with_result( result.it );
else
error();
Can't comment on C++11 but the Python version is better written as:
type = "foo"
try:
target_widget = (x for x in widgets if x.get_type() == type).next()
print "widget found:",target_widget
except StopIteration:
print "widget not found"
Um... maybe it's verbose because you're trying to be too clever? :-P How about
auto it = channel_widgets.begin();
while (it != channel_widgets.end())
if (it->getType() == type) goto found;
// error
found: // whatever
I kinda hate myself every time I write such for-loop, but it's still more succint than any variant of find_if. Generally, I use "trivial" STL algorithms (find, find_if, for_each, ...) only if I can reuse the functor several times. Otherwise it's not worth the hassle.
PS: you can do it also without goto... use "break" after if, and after while you write
if (it == channel_widgets.end())
whatever; // not_found
A similar approach occurred to me as I was writing that example. (Using a range-based for loop, break on found.) I guess I'm mostly scratching my head trying to figure out find_if's place in the universe.