Live data from Hacker News

Lambda expression comparison between C++11, C++14 and C++17

maitesin.github.io

11–20 of 87 posts

Re: Lambda expression comparison between C++11, C++14 and C++17

#11

A question people who use C++ regularly, is C++ becoming easier to read and code?

Yes, I work in a template heavy C++ codebase and the (already quite good) situation is getting better with each language standard.

C++11 was really a turning point for the language - features like 'auto', lambdas, and variadic templates have enabled succinct generic code that is both readable and highly performant.

Increased competition between the gcc and clang teams has also been a major improvement - both have implemented many C++17 features very quickly, and error messages have greatly improved in both compilers. This is especially welcome when developing templates. Clang's licensing has made it possible to integrate libclang in to vim/emacs (ycmd, irony-mode, rtags, etc) for very accurate completion/syntax checking, etc. Clang-format has also seen quite a bit of adoption, bringing the benefits of standardized formatting to large projects.

The sanitizers have also been a huge boon - getting automatic memory leak, buffer/heap overflow, use after free, uninitialized memory, integer overflow, etc is now as easy as compiling with '-fsanitize=[address|undefined|memory|etc]'.

Overall, C++(11+) is a very productive language if you have stringent performance and latency requirements and you need powerful abstraction facilities.

Re: Lambda expression comparison between C++11, C++14 and C++17

#13
post #10

Taking a concept such as a lambda function and making it look this ugly...this is why I hate C++. I wish I wasn't forced to program it every day.

How is it ugly? The capture list is a necessary complexity in a language with manual memory management.

Re: Lambda expression comparison between C++11, C++14 and C++17

#14
post #13
post #10

Taking a concept such as a lambda function and making it look this ugly...this is why I hate C++. I wish I wasn't forced to program it every day.

How is it ugly? The capture list is a necessary complexity in a language with manual memory management.

It's a trade off more than a necessity. For example, Rust doesn't have explicit capture lists, and if you want explicit control, you make new bindings and capture those. You almost never need to do this in Rust, so it's optimized for that case; I haven't written many closures in C++, so I can't say as much about the frequency there.

To make this more concrete:

    let s = String::from("s");
    
    let closure = || {
        println!("s is: {}", s);
    };
    
    closure();
If you wanted to capture s in a different way:

    let s = String::from("s");
    
    let s1 = &s;
    let closure = || {
        println!("s1 is: {}", s1);
    };
    
    closure();
No capture list needed, same control.

Re: Lambda expression comparison between C++11, C++14 and C++17

#15
post #13
post #10

Taking a concept such as a lambda function and making it look this ugly...this is why I hate C++. I wish I wasn't forced to program it every day.

How is it ugly? The capture list is a necessary complexity in a language with manual memory management.

The syntax is not the prettiest, but it is legible once you understand what [](){} means.

In C#, there is no such thing, but there is a part of me that wishes we had such a thing. I like the ability explicitly state what variables are being captured.

Re: Lambda expression comparison between C++11, C++14 and C++17

#16
post #13
post #10

Taking a concept such as a lambda function and making it look this ugly...this is why I hate C++. I wish I wasn't forced to program it every day.

How is it ugly? The capture list is a necessary complexity in a language with manual memory management.

Very often the capture list is empty, it could have been elided (as the parameter list can be) if the syntax could have been made unambiguous.

Re: Lambda expression comparison between C++11, C++14 and C++17

#17
post #13

Earlier quoted context omitted.

How is it ugly? The capture list is a necessary complexity in a language with manual memory management.

It's a trade off more than a necessity. For example, Rust doesn't have explicit capture lists, and if you want explicit control, you make new bindings and capture those. You almost never need to do this in Rust, so it's optimized for that case; I haven't written many closures in C++, so I can't say as much about the frequency there. To make this more concrete: let s = String::from("s"); let closure = || { println!("s…

Rust doesn't have explicit capture lists, but it does have the `move` modifier on closures which is like C++'s `[=]`.

Strictly speaking, Rust probably could have gotten away with having neither the `move` modifier nor capture clauses at all, but it would have had wide-ranging implications on the ergonomics and capabilty of closures.

Re: Lambda expression comparison between C++11, C++14 and C++17

#18
post #16
post #13

Earlier quoted context omitted.

How is it ugly? The capture list is a necessary complexity in a language with manual memory management.

Very often the capture list is empty, it could have been elided (as the parameter list can be) if the syntax could have been made unambiguous.

Well, you need something to indicate the beginning of a lambda. So you can think of "[]" as serving that role, instead of "lambda" in Python or "\" in Haskell.

Re: Lambda expression comparison between C++11, C++14 and C++17

#19
post #13

Earlier quoted context omitted.

How is it ugly? The capture list is a necessary complexity in a language with manual memory management.

It's a trade off more than a necessity. For example, Rust doesn't have explicit capture lists, and if you want explicit control, you make new bindings and capture those. You almost never need to do this in Rust, so it's optimized for that case; I haven't written many closures in C++, so I can't say as much about the frequency there. To make this more concrete: let s = String::from("s"); let closure = || { println!("s…

How would you do the equivalent of this in Rust?

  auto on_heap = std::make_unique(...);

  function_that_accepts_lambda([obj = std::move(on_heap)]() {
     obj->bar(...);
  })

Re: Lambda expression comparison between C++11, C++14 and C++17

#20
post #19

Earlier quoted context omitted.

It's a trade off more than a necessity. For example, Rust doesn't have explicit capture lists, and if you want explicit control, you make new bindings and capture those. You almost never need to do this in Rust, so it's optimized for that case; I haven't written many closures in C++, so I can't say as much about the frequency there. To make this more concrete: let s = String::from("s"); let closure = || { println!("s…

How would you do the equivalent of this in Rust? auto on_heap = std::make_unique (...); function_that_accepts_lambda([obj = std::move(on_heap)]() { obj->bar(...); })

    let on_heap = Box::new(...);

    function_that_accepts_lambda(move || {
        on_heap.bar();
    });
This is sort of what kibwen was mentioning: move is a single annotation that overrides everything to capture by value rather than have it inferred.
Post reply on HN