Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling a function from within a boost::phoenix::lambda

I am trying to use boost::phoenix to emulate C++ lambda expressions on an older compiler that lacks C++11 support, and I am unable to call a simple function from within a lambda expression.

C++11 Version:

[](unsigned a) { foo( a ); }( 12678u );   // calls foo( 12678u )

My Phoenix Lambda code is as follows:

#include <cstdint>
#include <iostream>
#include <boost/phoenix.hpp>

namespace ph = boost::phoenix;
using ph::local_names::_a;
using ph::placeholders::arg1;

void foo( uint32_t val )
{
   std::cout << "\t" << __func__ << "( " << val << " ) called...\n";
}

int main()
{
   auto myLambda = ph::lambda( _a = arg1 )
      [
          foo( _a )
          //std::cout << ph::val( "Called with: " ) << _a << ph::val( "\n" )
      ]( 567u );

   myLambda();

    return 0;
}

This produces the following compiler error:

lambda-ex.cpp: In function ‘int main()’:
lambda-ex.cpp:18:19: error: cannot convert ‘const _a_type {aka const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tag::terminal, boost::proto::argsns_::term<boost::phoenix::detail::local<boost::phoenix::local_names::_a_key> >, 0l> >}’ to ‘uint32_t {aka unsigned int}’ for argument ‘1’ to ‘void foo(uint32_t)’ lambda-ex.cpp:20:15: error: unable to deduce ‘auto’ from ‘<expression error>’

How do I call a function from within a Phoenix lambda expression?

I am hoping to be able to use phoneix::lambdas in the same way that I have used C++11 lambdas in the past, e.g.:

auto lambda1 = [&]( uint32_t arg )
              {
                  func1( "Some Stuff", arg );
                  func2( "Some More Stuff", aValueFromLocalScope, arg );
                  func3( "Some Stuff", anotherValueFromLocalScope, arg );
              };

someFuncImpl( aParam, lambda1 );
like image 209
mark Avatar asked Dec 26 '22 06:12

mark


2 Answers

ph::lambda is the wrong tool for this job (ph::lambda is a tool for creating nested lambda expressions inside a phoenix expression). Phoenix expressions are already functions, so all that you need to do is find a way to call functions using phoenix expressions (bind), find a way to execute multiple operations in sequence (operator,), and find a way to introduce local variables (let). Putting this all together gives:

#include <cstdint>
#include <iostream>
#include <boost/phoenix.hpp>

namespace ph = boost::phoenix;
using ph::local_names::_a;
using ph::placeholders::arg1;

#define FOO(name) void name( uint32_t val ) {\
    std::cout << "\t" << __func__ << "( " << val << " ) called...\n";\
}
FOO(foo)
FOO(bar)
FOO(baz)

int main()
{
    auto&& myLambda = ph::let(_a = arg1)
      [
          ph::bind(foo, _a),
          ph::bind(bar, _a),
          ph::bind(baz, _a)
      ];

    myLambda(342);

    return 0;
}
like image 102
Mankarse Avatar answered Dec 29 '22 04:12

Mankarse


It doesn't matter if your example is trivial or not. Calling non-Phoenix functions requires using phoenix::bind. Period.

Phoenix-style lambdas are most effectively used for simple operator-overloading-based expressions. Calling arbitrary functions will look ugly.

C++11 did not add lambdas as a language feature because it was fun. They did it because the various library solutions were all inadequate in some way. You have found one of the inadequacies of Phoenix.

like image 27
Nicol Bolas Avatar answered Dec 29 '22 02:12

Nicol Bolas