#find_if lambda, if you please

75 messages · Page 1 of 1 (latest)

compact creek
#

Cannot get the commented lambda to work. Could only work out how to do this using a good-old functor. Can it be done?

#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <string>

struct find_first_not_of
{
    find_first_not_of(std::string const& str) : str_(str) {}

    bool operator()(char ch) const {
        auto f = str_.find(ch);
        return f == std::string::npos;
    }

    const std::string& str_;
};

int main()
{
    const char str[] = "   aaa bbb   ";

    // auto find_first_not_of = [&ch](std::string const& str) -> bool
    // {
    //     return !str.find(ch);
    // };

    auto f = std::find_if(std::cbegin(str), std::cend(str), find_first_not_of(" \t\n\r\f\v"));
    if (f != std::cend(str)) {
        std::cout << std::distance(std::cbegin(str), f) << std::endl;
    }
}
abstract sandalBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

fringe elk
#

You got captures and parameters wrong way around

compact creek
#

But how can I effectively construct the lambda with a string of chars to search?

#

Like I do with my functor.

#

I know I can create that string before the lambda definition and capture locals.

fringe elk
#

Ah, sorry, gotcha.

auto find_first_not_of = [](std::string str)
{
    return [str = std::move(str)](char ch)
    {
        return !str.find(ch);
    };
};
compact creek
#

Where does the lambda get the ch from though?

fringe elk
#

It is a parameter of a nested lambda

compact creek
#

Ah, nested lambda.
Sorry, bit slow there.

#

Hang on, where are we capturing the char (from my string literal) to test?

#

Starting to think that the functor is the neatest solution in this scenario.

bleak canopy
#

not sure what you're trying to achieve tbh

#

if you want to treat the thing like a type, might as well have one, in particular if you're gonna use it in various places

#

if you have one place of usage, you can have a local type or a lambda, but then I'd argue that usually you don't need to have a lambda factory

fringe elk
bleak canopy
#

I feel like there's some confusion about between the string being traversed and the string providing the characters to find/exclude/whatever you want to call it

compact creek
#

Yes and no.
I can construct a functor with the "exclusion" chars.
It appears that is not possible with a lambda?

fringe elk
#

Hm, but I've shown how to do it with a lambda

#

The syntax is exactly what you have with your functor

bleak canopy
compact creek
bleak canopy
#

a "lambda expression" automatically produces you an object of the anonymous lambda type

compact creek
#

I mean the char that we are testing.

bleak canopy
#

you don't usually construct it or whatever like you would a regular type

#

if you want to contextually customize some stuff, you have to do so throught the capture list

bleak canopy
#

and hbc wrapped the hole thing in an outer lambda that acts as a "lambda factory"

bleak canopy
#

that's what I called a "lambda factory"

compact creek
#

It feels like I am better off with the functor, no?

bleak canopy
#

not enough context imo

#

either way you produce a function object type that takes a char and returns a bool

#

hbc version's is arguably better in that it has fewer risk of dangling

compact creek
#

But the functor can be construction-initialized with the strings of char to ignore.

bleak canopy
#

because your version creates a string temporary, bind it to a reference, and in the wrong context the string dies and your reference is having fun

#

considering you already create the string either way because of temporary materialization might as well keep it in the function object

bleak canopy
#

it's just unclear to what extent the lambda / lambda factory should be exposed

fringe elk
compact creek
fringe elk
#

Yeah

#

[str = std::move(str)](char ch)
Here str = ... becomes a field like in your functor. = std::move(str) is what it's set to (think of it as a constructor argument)

#

(char ch) is the parameter list of an operator(), so again exactly like your functor

compact creek
#

I know not how your lambda works / should work.
That's the whole point of this thread; I certainly cannot make one work the way I want it to.

I can only do it with a functor.
But functors are old hat, so if a lambda can do the same, then I would go with the lambda.
If a lambda cannot do what the functor can (here), then at least I can defend the decision to stick with the functor.

bleak canopy
fringe elk
#

Ah I trusted your !str.find(ch) nooo

bleak canopy
#

like if you wanted a carbon copy of your functor you'd &str_ = str in the lambda capture as well

#

and you'd essentially copy-paste the functor operator() body into the nested lambda body

fringe elk
bleak canopy
#

a lambda is a functor

#

in the sense that either way you have a function object

compact creek
#

Agreed, but you don't with / for certain individuals that I do.

bleak canopy
#

imo the places where you'll need to use the "factory" matters more

#

like personally I'd balk at having a global object to use as a lambda factory

#

I'd rather have a type or a factory function

compact creek
#

I think I will fight for the type / function object / functor that I have now.

#

Sometimes you have to push back at the authorities.

bleak canopy
#

I mean I don't like your functor in its current state tbh

compact creek
#

Go on...

bleak canopy
#

I'd much rather use a lambda if you create the function object in one place as well

#

because it's fewer ways to screw up

#

with all the const/non-const noexcept/constexpr whatever

bleak canopy
# compact creek Go on...

well I already complained about dangling earlier, but I have another bit that annoys me which relates to whether you will only ever use that thing with string literals or also with other things

#

if I had to tl;dr I guess this mostly boils down various optimization issues with string allocation

compact creek
bleak canopy
#

I guess? that doesn't really answer my questions about string literals and the need to instantiate lambdas/predicates/function objects in a bunch of distinct place (or not)

#

iirc you're stuck with c++14 so I assume the string view at the end is mostly for illustration purposes

#

if you wished to use an explicit type, then my "annoyance" wrt dangling would be solved by just having the string member be "by-value" rather than "by-reference"

compact creek
#

!solved