Domanda

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 );
È stato utile?

Soluzione

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;
}

Altri suggerimenti

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top