views:

103

answers:

2

I've just rewritten the following C89 code, that returns from the current function:

// make sure the inode isn't open
{
    size_t i;
    for (i = 0; i < ARRAY_LEN(g_cpfs->htab); ++i)
    {
        struct Handle const *const handle = &g_cpfs->htab[i];
        if (handle_valid(handle))
        {
            if (handle->ino == (*inode)->ino)
            {
                log_info("Inode "INO_FMT" is still open, delaying removal.",
                        (*inode)->ino);
                return true;
            }
        }
    }
}

With this C++0x STL/lambda hybrid:

std::for_each(g_cpfs->htab.begin(), g_cpfs->htab.end(), [inode](Handle const &handle) {
    if (handle.valid()) {
        if (handle.ino == inode->ino) {
            log_info("Inode "INO_FMT" is still open, delaying removal.", inode->ino);
            return true;
        }
    }});

Which generates:

1>e:\src\cpfs4\libcpfs\inode.cc(128): error C3499: a lambda that has been specified to have a void return type cannot return a value

I hadn't considered that the return in the lambda, doesn't actually return from the caller (having never seen a scoped function in C/C++ before now). How do I return true from the caller where the original function would have done so?

+5  A: 

You don't; std::for_each isn't structured to handle an early return. You could throw an exception...

Or don't use a lambda:

for (auto const &handle : g_cpfs->htab) {
  // code that was in lambda body
}
Roger Pate
Note "range-based for loops" (as the 0x draft calls them) are "foreach loops", which is what you were trying to get from std::for_each.
Roger Pate
The foreach syntax is precisely what I was looking for.
Matt Joiner
yeah, I removed that comment again. I assumed he meant `for_each` syntax. :)
jalf
+2  A: 

Use std::find_if() instead of std::for_each():

if (std::find_if(g_cpfs->htab.begin(), g_cpfs->htab.end(),
        [inode](Handle const &handle) {
            if (handle.valid() && handle.ino == inode->ino) {
                log_info("Inode "INO_FMT" is still open, delaying removal.",
                    inode->ino);
                return true;
            }
            return false;
        }) != g_cpfs->htab.end()) {
    return true;
}
Frédéric Hamidi
While find_if does work at fixing the loop impedance mismatch, using it with if and the return values like that feels wrong.
Roger Pate
@Roger, yup, I also had to use pretty weird indentation to make it readable. It works, though, so I don't know if that's really an issue...
Frédéric Hamidi
It does feel weird, but this is the best way to do it, given that MSVC2010 doesn't seem to support range-based for?
Matt Joiner
@Matt, or you could wait for VC++ 2011 ;)
Frédéric Hamidi
@Matt: BOOST_FOREACH? (You can also copy the code for MSVC, Boost is *very* liberally licensed.) "Regular" begin/end for loop?
Roger Pate