Reputation: 15295
I would expect the following example Boost Phoenix expression to compile.
What am I missing?
int plus(int a,int b)
{
return a+b;
}
void main(int argc,char** argc)
{
auto plus_1 = phx::bind(&plus,1,arg1);
auto value = phx::lambda[phx::val(plus_1)(arg1)]()(1);
std::cout << value << std::endl;
}
Upvotes: 0
Views: 228
Reputation: 6177
auto plus_1 = phx::bind(&plus,1,arg1);
After this line, plus_1
is a function object that takes one int
argument and adds one to it.
phx::lambda[plus_1(arg1)](1);
Whoops. This isn't going to work because (as we said above) plus_1
is a function object that takes one int
argument and adds one to it. Here, you're trying to invoke it with arg1
.
It isn't obvious from your code what you expect it to do. Can you clarify?
====EDIT====
I see you've edited the code in your question. Your code is still wrong but for a different reason now. This:
phx::val(plus_1)(arg1)
... uses val
to create a nullary function that returns the plus_1
unary function. You then try to invoke the nullary function with arg1
. Boom.
Here is code that executes and does (what I believe) you intend:
#include <iostream>
#include <boost/phoenix/phoenix.hpp>
namespace phx = boost::phoenix;
using phx::arg_names::arg1;
int plus(int a,int b)
{
return a+b;
}
int main()
{
auto plus_1 = phx::bind(&plus, 1, arg1);
int value = phx::bind(phx::lambda[plus_1], arg1)(1);
std::cout << value << std::endl;
}
The first bind
takes the binary plus
and turns it into a unary function with the first argument bound to 1
. The second bind
creates a new unary function that is equivalent to the first, but it does so by safely wrapping the first function using lambda
. Why is that necessary? Consider the code below, which is equivalent, but without the lambda
:
// Oops, wrong:
int value = phx::bind(phx::bind(&plus, 1, arg1), arg1)(1);
Notice that arg1
appears twice. All expressions get evaluated from the inside out. First, we'll bind the inner arg1
to 1
, then evaluate the inner bind
yielding 2
, which we then try to bind and invoke. That's not going to work because 2
isn't callable.
The use of lambda
creates a scope for the inner arg1
so it isn't eagerly substituted. But like I said, the use of the second bind
, which forces the need for lambda
, yields a function that is equivalent to the first. So it's needlessly complicated. But maybe it helped you understand about bind
, lambda
and Phoenix scopes.
Upvotes: 4
Reputation: 473477
Perhaps this can explain it better.
Phoenix is not magic; it is first and foremost C++. It therefore follows the rules of C++.
phx::bind
is a function that returns a function object, an object which has an overloaded operator()
that calls the function that was bound. Your first statement stores this object into plus_1
.
Given all of this, anytime you have the expression plus_1(...)
, this is a function call. That's what it is; you are saying that you want to call the overloaded operator()
function on the type of that object, and that you are going to pass some values to that function.
It doesn't matter whether that expression is in the middle of a []
or not. phx::lambda
cannot make C++ change its rules. It can't make plus_1(...)
anything other than an immediate function call. Nor can arg1
make plus_1(...)
not an immediate function call.
Upvotes: 1
Reputation: 62975
It's not clear to me what you're trying to accomplish by using lambda
here, but if you just want to call plus_1
with 1
(resulting in 2
), it's much simpler than your attempt:
#include <iostream>
#include <boost/phoenix.hpp>
int plus(int a, int b)
{
return a + b;
}
int main()
{
namespace phx = boost::phoenix;
auto plus_1 = phx::bind(plus, 1, phx::arg_names::arg1);
std::cout << plus_1(1) << '\n';
}
If this isn't what you're trying to accomplish, then you need to describe what you actually want. :-]
Upvotes: 2