Hacker News new | past | comments | ask | show | jobs | submit login

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"


You can also use the `next(x for x in ...)` form where you can even supply a default value.


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.


boost::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;
    }




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: