LiKao
LiKao

Reputation: 10658

How to handle lambdas in a pre-lambda compiler

I have some code that can greatly be reduced in complexity by using lambdas. However unfortunately we have to use a compiler that does not fully support C++11 and we cannot easily switch. Now the question is how to keep the logic as close as possible to a lambda-expression with features not available (i.e. std::function is available, lambdas are not).

The usual solution is to define the functor somewhere else and then use it at the appropriate place:

struct functor{
   functor( type & member ) : m_member( member ) {}
   void operator()( ... ) {...}
   type & m_member;
};

void function() {
   use_functor( functor(...) );
}

I am very much used to this pattern, although I dislike it a lot. The main reason for not defining the class is usually that I the functor will be used within a STL and templates do not like structs defined inline of a function. However in my case the use_functor() function will be a normal method, so I can define the functor inside of the function itself (each functor is only used within one function).

void function() {
   struct functor{
      functor( type & member ) : m_member( member ) {}
      void operator()( ... ) {...}
      type & m_member;
   };
   use_functor( functor(...) );
}

This seems somewhat improved, but still requires a lot more ugly code that I would like. For example I would like to get rid of the name of the functor altogether. I know it is possible to create an anonymous struct, if I only ever use one value.

void function() {
   struct{
      // functor( type member ) : m_member( member ) {}
      void operator()( ... ) {...}
      // type & m_member;
   } callback ;
   use_functor( callback );
}

However at this point I have no clue on how to provide the necessary data members. Since the struct is anonymous it does not have a constructor. I could easily set the member, because it is public, but again this would add a line which I dislike.

The goal is to leave it in a state that as little as possible needs to be changed once we switch to a compiler that has clean lambdas which would allow to eliminate this problem altogether.

How would you go about doing this?

Upvotes: 5

Views: 267

Answers (3)

Michael Price
Michael Price

Reputation: 9018

Expanding on the answer by awoodland:

#define MY_LAMBDA(name, memberType, memberValue, body) \
    struct {                                     \
        void operator()( ... ) body              \
        memberType & memberValue;                   \
    } name = {memberValue}

void function() {
    type thing_to_capture;

    MY_LAMBDA(callback, type, thing_to_capture
    {
        std::cout << thing_to_capture << std::endl;
    });

    use_functor( callback );
}

You can use MY_LAMBDA anywhere you can define a struct. Unfortunately, without variadic macros, you have to wrap all captured objects into a single object, and you have to specify the type of that object in the "lambda declaration"

Also note that the equivalent using a lambda would be:

void function() {
    type thing_to_capture;

    auto callback = [&thing_to_capture]()
    {
        std::cout << thing_to_capture << std::endl;
    };

    use_functor( callback );
}

Upvotes: 0

codemaker
codemaker

Reputation: 1742

You could try boost lambda library or boost::phoenix. They are both designed to do lambda style operations without actual lambda support. Since they are template based, errors can be difficult to debug when something doesn't work as expected.

Upvotes: 0

With regards to the initalisation of the member variables of an anonymous struct without a constructor you can do:

void function() {
   type the_thing;
   struct {
      void operator()( ... ) {...}
      type & m_member;
   } callback = {the_thing};
   use_functor( callback );
}

to set the type & reference m_member in callback.

Upvotes: 1

Related Questions