Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda functions as base classes

Tags:

c++

c++11

lambda

Playing around with Lambdas I found an interesting behaviour that I do not fully understand.

Supose I have a struct Overload that derives from 2 template parameters, and has a using F1::operator(); clause.

Now if I derive from two functors I can only access the operator() of F1 (as I would expect)

If I derive from two Lambda Functions this is no longer true: I can access the operator() from F2 too.

#include <iostream>  // I compiled with g++ (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8) // // g++ -Wall -std=c++11 -g main.cc // g++ -Wall -std=c++11 -DFUNCTOR -g main.cc //  // or clang clang version 3.3 (tags/RELEASE_33/rc2) //  // clang++ -Wall -std=c++11 -g main.cc // clang++ -Wall -std=c++11 -DFUNCTOR -g main.cc //  // on a Linux localhost.localdomain 3.9.6-200.fc18.i686 #1 SMP Thu Jun 13  // 19:29:40 UTC 2013 i686 i686 i386 GNU/Linux box   struct Functor1 {     void operator()() { std::cout << "Functor1::operator()()\n"; } };  struct Functor2 {     void operator()(int) { std::cout << "Functor2::operator()(int)\n"; } };  template <typename F1, typename F2> struct Overload : public F1, public F2 {     Overload()         : F1()         , F2() {}      Overload(F1 x1, F2 x2)         : F1(x1)         , F2(x2) {}      using F1::operator();  };  template <typename F1, typename F2> auto get(F1 x1, F2 x2) -> Overload<F1, F2> {    return Overload<F1, F2>(x1, x2); }   int main(int argc, char *argv[]) {     auto f = get(Functor1(), Functor2());      f(); #ifdef FUNCTOR     f(2); // this one doesn't work IMHO correctly #endif      auto f1 = get(                   []() { std::cout << "lambda1::operator()()\n"; },                   [](int) { std::cout << "lambda2::operator()(int)\n"; }                   );     f1();     f1(2); // this one works but I don't know why     return 0; } 

The standard states that:

The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non- union class type

So every Lambda's types should be unique.

I cannot explain why this is so: can anyone shed some light on this please?

like image 287
gu1d0 Avatar asked Aug 25 '13 18:08

gu1d0


People also ask

Are lambdas same as closures?

Java supports lambda expressions but not the Closures. A lambda expression is an anonymous function and can be defined as a parameter. The Closures are like code fragments or code blocks that can be used without being a method or a class.

Is a lambda function a closure?

Lambda functions may be implemented as closures, but they are not closures themselves. This really depends on the context in which you use your application and the environment. When you are creating a lambda function that uses non-local variables, it must be implemented as a closure.

Are lambdas always Inlined?

All lambdas are inline. Not all calls to them are necessarily inlined.

What is base class function?

The Base class members and member functions are inherited to Object of the derived class. A base class is also called parent class or superclass. Derived Class: A class that is created from an existing class. The derived class inherits all members and member functions of a base class.


1 Answers

In addition to operator(), a the class defined by a lambda can (under the right circumstances) provide a conversion to a pointer to function. The circumstance (or at least the primary one) is that the lambda can't capture anything.

If you add a capture:

auto f1 = get(               []() { std::cout << "lambda1::operator()()\n"; },               [i](int) { std::cout << "lambda2::operator()(int)\n"; }               ); f1(); f1(2); 

...the conversion to pointer to function is no longer provided, so trying to compile the code above gives the error you probably expected all along:

trash9.cpp: In function 'int main(int, char**)': trash9.cpp:49:9: error: no match for call to '(Overload<main(int, char**)::<lambda()>, main(int, char**)::<lambda(int)> >) (int)' trash9.cpp:14:8: note: candidate is: trash9.cpp:45:23: note: main(int, char**)::<lambda()> trash9.cpp:45:23: note:   candidate expects 0 arguments, 1 provided 
like image 62
Jerry Coffin Avatar answered Sep 23 '22 13:09

Jerry Coffin