3 ms·
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 exam
by simmons 14y ago
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!)
- reinhardt 14y agoCan'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"
- kzrdude 14y agoYou can also use the `next(x for x in ...)` form where you can even supply a default value.
- dfbrown 14y agoboost::range can makes a bit less verbose: std::string type("foo"); auto range = channel_widgets | filter([type](const std::shared_ptr<Widget> &w) { return w->getType() == type; }); if (range) { std::string target_widget = *range.begin(); std::cout << "widget found." << std::endl; } else { std::cerr << "widget not found" << std::endl; }
- stinos 14y ago"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();
- zvrba 14y agoUm... 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
- simmons 14y agoA 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.