4

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 );
mark
  • 7,381
  • 5
  • 36
  • 61
  • Use [bind](http://liveworkspace.org/code/aHc9d$10). – Mankarse Apr 06 '13 at 13:43
  • @Mankarse This is a trivial example - I do not want to simply replace the lambda with `boost::phoenix::bind( &foo, arg1 )` - I am trying to use `phoneix::lambda` to emulate C++ 11 lambdas. – mark Apr 06 '13 at 13:48
  • It seems that my suggestion was poorly thought out. [here](http://liveworkspace.org/code/aHc9d$14) is an updated version that introduces a local variable and calls multiple functions. – Mankarse Apr 06 '13 at 13:58
  • `ph::lambda` is not what you want. `ph::lambda` is for introducing (meta)-lambda expressions into a phoenix expression (phoenix expressions are themselves already lambda-expressions). (You might want to do this if you wanted to write a phoenix function that, when called, called another function with a function defined within the phoenix expression). – Mankarse Apr 06 '13 at 14:02
  • @Mankarse - `ph::let` as per your example is just what I want. Thanks - can you paste as an answer and I will accept it. – mark Apr 06 '13 at 14:09

2 Answers2

6

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;
}
Mankarse
  • 39,818
  • 11
  • 97
  • 141
4

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.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982