• Like
Fun with Lambdas: C++14 Style (part 2)
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

Fun with Lambdas: C++14 Style (part 2)

  • 25,706 views
Published

Look at some interesting examples of C++14 lambdas and how they interact with other language features and libraries.

Look at some interesting examples of C++14 lambdas and how they interact with other language features and libraries.

Published in Education
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
25,706
On SlideShare
0
From Embeds
0
Number of Embeds
87

Actions

Shares
Downloads
56
Comments
1
Likes
7

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Sumant Tambe, Ph.D. Microsoft Visual C++ MVP Senior Software Research Engineer Real-Time Innovations, Inc. @sutambe SFBay Association of C/C++ Users April 9, 2014
  • 2. Author Blogger Open-Source Contributor LEESA Rx4DDS.NET Reflection for DDS-XTypes
  • 3. » Functional Programming eXchange » Strange Loop » ReactConf » LambdaConf » LambdaJam » CraftConf » MSFT MVP Summit » Qcon NYC/SF/London » Closure West » Spring into Scala » Progressive F# » FP Days » SkillsMatter
  • 4. » Lambda Expressions ˃ expr.prim.lambda » Anonymous functions void abssort(float* x, unsigned N) { std::sort(x, x + N, [](float a, float b) { return std::abs(a) < std::abs(b); }); }
  • 5. class Comp { float a; public: Comp(float x) { a = x; } bool compare(float b) const { return std::abs(a) < std::abs(b); } }; float array[5] = { 0, 1, 2, 3, 4 }; float a = 3; Comp f(a); for(float item : array) std::cout << std::boolalpha << f.compare(item);
  • 6. class Comp { float a; public: Comp(float x) { a = x; } bool operator () (float b) const { return std::abs(a) < std::abs(b); } }; float array[5] = { 0, 1, 2, 3, 4 }; float a = 3; Comp f(a); for(float item : array) std::cout << std::boolalpha << f(item);
  • 7. class ##### { float a; public: Foo(float x) { a = x; } bool operator () (float b) const { return std::abs(a) < std::abs(b); } }; float array[5] = { 0, 1, 2, 3, 4 }; float a = 3; auto f = #####(a); for(float item : array) std::cout << std::boolalpha << f(item);
  • 8. class ##### { float a; public: Foo(float x) { a = x; } bool operator () (float b) const { return std::abs(a) < std::abs(b); } }; float array[5] = { 0, 1, 2, 3, 4 }; float a = 3; auto f = #####(a); auto f = [a](float b) { return std::abs(a) < std::abs(b) }; for(float item : array) std::cout << std::boolalpha << f(item);
  • 9. » Anonymous functions » Written exactly in the place where it's needed » Can access the variables available in the enclosing scope (closure) » May maintain state (mutable or const) » Can be passed to a function » Can be returned from a function » Deduce return type automatically » Accept generic parameter types (only in C++14) [a](auto b) { return std::abs(a) < std::abs(b) };
  • 10. » Associative containers and lambdas » Recursive Lambdas » Composable list manipulation » Scope Exit Idiom » Overloaded Lambdas » Type Switch (simple pattern matching) » Converting shared_ptr between boost and std » In-place parameter pack expansion » Memoization
  • 11. » Associative containers: set, map, multiset, multimap ˃ Use comparators ˃ Example, std::set<int, std::less<int>> » Can comparators be a lambda? » std::set<int, ???> » Use std::function as the comparator type std::set<int, std::function<bool(int, int)>> numbers([](int i, int j) { return i < j; }); » Small-closure optimization may kick in ˃ Check you compiler manual
  • 12. auto make_fibo() { std::function<int(int)> recurse; recurse = [&](int n){ return (n<=2)? 1 : recurse(n-1) + recurse(n-2); }; return recurse; } int main() { auto fibo = make_fibo(); std::cout << fibo(10) << std::endl; // 55 return 0; }
  • 13. auto make_fibo() { return [](int n) { std::function<int(int)> recurse; recurse = [&](int n){ return (n<=2)? 1 : recurse(n-1) + recurse(n-2); }; return recurse(n); }; } int main() { auto fibo = make_fibo(); std::cout << fibo(10) << std::endl; // 55 return 0; }
  • 14. IList<Box> boxes = /* ... */; int sumOfWeights = boxes.Where(b => b.Color == Color.RED) .Select(b => b.Weight) .Count(); List<Box> boxes = /* ... */; int sumOfWeights = boxes.stream() .filter(b -> b.getColor() == Color.RED) .map(b -> b.getWeight()) .sum(); C# Java8
  • 15. » Example cpplinq (http://cpplinq.codeplex.com) Box boxes[] = { … }; int sum_of_weights = cpplinq::from_array(boxes) >> where([](const Box & box) { return box.color == Color.RED; }) >> select([](const Box & box) { return box.get_weight(); }) >> count();
  • 16. » Restriction Operators ˃ Where » Projection Operators ˃ ref, select, select_many » Partitioning Operators ˃ take, take_while, skip, skip_while » Join Operators ˃ Join » Concatenation Operators ˃ Concat » Ordering Operators ˃ orderby, orderby_ascending or orderby_descending » Set Operators ˃ distinct, union_with, intersect_with, except » Set Operators ˃ distinct, union_with, intersect_with, except » Conversion Operators ˃ to_vector, to_list, to_map, to_lookup » Element Operators ˃ first, first_or_default, last_or_default » Generation Operators ˃ range, repeat, empty, singleton, generate, » Quantifiers ˃ any, all, contains, » Aggregate Operators ˃ Count, sum, min, max, avg, aggregate » Other ˃ pair_wise, zip_with
  • 17. » Cpplinq http://cpplinq.codeplex.com/ » Narl (Not another range library) https://github.com/essennell/narl » boost.range http://www.boost.org/doc/libs/1_54_0/libs/range/ » Linq http://pfultz2.github.io/Linq/ » boolinq http://code.google.com/p/boolinq/ » lx++ (part of Native-RX) https://rx.codeplex.com/ » Linq++ https://github.com/hjiang/linqxx/ » oven http://p-stade.sourceforge.net/oven/ » cpplinq (same name but unrelated) http://code.google.com/p/cpplinq/ » linq https://bitbucket.org/ronag/cppextras/src/master/linq/linq.hp p
  • 18. » Language for Embedded Query and Traversal » Tree Traversal ˃ For XML data-binding code generators ˃ Visitors » Think XPath queries embedded in C++ ˃ Typed (not string encoded) » Generic Programming ˃ Expression Templates ˃ Meta-programming ˃ C++ Concepts (no longer in C++11) http://www.dre.vanderbilt.edu/LEESA/
  • 19. <catalog> <book> <title>…</title> <price>…</price> <author> <name>…</name> <country>…</country> </author> </book> <book>...</book> ... </catalog> LEESA: std::vector<name> author_names = eval(root, catalog() >> book() >> author() >> name()); XPath: "/book/author/name/text()"
  • 20. » Find names of authors from USA » XPath: “//author[country/text() = ‘USA’]/name/text()” » LEESA: Catalog croot = load_catalog(“catalog.xml”); std::vector<Name> author_names = eval(croot, Catalog() >> DescendantsOf(Catalog(), Author()) >> Select(Author(), [](const Author &a) { return a.get_country() == “USA”; }) >> Name());
  • 21. int main() { std::mutex m; m.lock(); SCOPE_EXIT(m.unlock()); /* Potential exceptions here */ return 0; } Example only. Prefer std::lock_guard Scope exit idiom ensures that resources are released
  • 22. template <typename F> struct ScopeExit { ScopeExit(F f) : f(f) {} ~ScopeExit() { f(); } F f; }; template <typename F> ScopeExit<F> MakeScopeExit(F f) { return ScopeExit<F>(f); }; #define DO_STRING_JOIN(arg1, arg2) arg1 ## arg2 #define SCOPE_EXIT(code) auto STRING_JOIN(scope_exit_, __LINE__) = MakeScopeExit([&](){code;})
  • 23. » Can you really do that!? ˃ As it turns out, YES! template <class... F> struct overload : F... { overload(F... f) : F(f)... {} }; template <class... F> auto make_overload(F... f) { return overload<F...>(f...); } auto f = make_overload([](int i) { /* print */ }, [](double d) { /* print */ }); f(10); f(9.99);
  • 24. struct Base {}; struct Derived : Base {}; template <class Poly> void test(Poly& p) { match(p)( [](int i) { cout << “int”; }, [](std::string &) { cout << “string”; }, [](Base &) { cout << "Base"; }, [](Derived &) { cout << "Derived"; }, otherwise([](auto x) { cout << "Otherwise”; }) ); } test(10); // int test(std::string(“C++ Truths”)); // string test(Derived()); // Derived test(9.99); // Otherwise
  • 25. » Boost and std::shared_ptr manage memory automatically » They both use their own reference counters » What happens when you convert from boost to std shared_ptr or vice versa template <typename T> boost::shared_ptr<T> make_shared_ptr(std::shared_ptr<T> ptr) { return boost::shared_ptr<T>(ptr.get()); } » Hint: They both support deleters ˃ malloc = allocator ˃ free = deleter std::shared_ptr<char> buf((char *)malloc(10), free);
  • 26. template <typename T> boost::shared_ptr<T> make_shared_ptr(std::shared_ptr<T> ptr) { return boost::shared_ptr<T>(ptr.get(), [ptr](T*) mutable { ptr.reset(); }); } template <typename T> std::shared_ptr<T> make_shared_ptr(boost::shared_ptr<T> ptr) { return std::shared_ptr<T>(ptr.get(), [ptr](T*) mutable { ptr.reset(); }); }
  • 27. void no_op(...) { } template <class... T> void foreach(T... args) { no_op([=](){ cout << args << "n"; return true; }()...); } foreach(10, 20.2, true);
  • 28. » Avoid repeated calculations by caching function results template <typename ReturnType, typename... Args> auto memoize(ReturnType (*func)(Args...)) int fibo(int) { … } int main() { auto mem_fibo = memoize(fibo); std::cout << “Compute” << mem_fibo(10); std::cout << “Lookup” << mem_fibo(10); }
  • 29. » Avoid repeated calculations by caching function results template <typename ReturnType, typename... Args> auto memoize(ReturnType (*func)(Args...)) { std::map<std::tuple<Args...>, ReturnType> cache; return ([=](Args... args) mutable { std::tuple<Args...> t(args...); if (cache.find(t) == cache.end()) { std::cout << "not foundn"; cache[t] = func(args...); } return cache[t]; }); }