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

9:31:00 PM 0 Comments A+ a-


Look at some interesting examples of C++11/14 lambdas and how they interact with other language features and libraries. I hope to find some time to add some explanations. See part 1 if you missed it.

  • Associative containers and lambdas
    std::set<int, std::function<bool(int, int)>> 
      numbers([](int i, int j) { return i < j; });
  • Recursive Lambdas (see Creating recursive lambdas and returning them too!)
    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);
      };
    }
  • Composable list manipulation (e.g., cpplinq, narl, LEESA)
    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();
         })
      >> sum();
    
  • Overloaded Lambdas
    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); // int 
    f(9.99); // double
  • Type Switch (simple pattern matching) (see type_switch.cpp and this paper)
    struct Base { 
      virtual ~Base() {} 
    };
    struct Derived : Base {};
    
    template <class Poly>
    void test(Poly& p) {  
      match(p)(
        [](int i)             { cout << "int";       },
        [](std::string &)     { cout << "string";    },
        [](Derived &)         { cout << "Derived";   },     
        [](Base &)            { cout << "Base";      },    
        otherwise([](auto x)  { cout << "Otherwise"; })
      );  
    }
    Derived d;
    Base &b = d;
    std::string cpptruths = "C++ Truths";
    boost::any something = cpptruths;
    
    test(10);        // int
    test(cpptruths); // string
    test(something); // string
    test(b);         // Derived
    test(9.99);      // Otherwise
  • Converting shared_ptr between boost and std (see StackOverflow)
    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(); });
    }
  • In-place parameter pack expansion 
    template <class... T>
    void foreach(T... args) 
    {  
      bool b[] = { [=](){ 
        std::cout << args << "\n"; 
        return true; 
      }()... }; 
    }
    
    foreach(10, 20.2, true);
  • Memoization (see original)
    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 found\n";
              cache[t] = func(args...);
            }
            return cache[t];
        });
    }
  • Finally, slides