
On Thu, Feb 19, 2004 at 03:46:01PM +0200, Peter Dimov wrote:
Brian McNamara wrote:
That is, you cannot write "app" so that both calls here:
int f(int); int g(int&); int x; ... app(_,3)(f); app(_,x)(g);
work properly. It's impossible.
Let's see if I get this right:
#include <boost/bind.hpp> #include <boost/bind/apply.hpp> #include <iostream>
int f(int x) { std::cout << "f(" << x << ")\n"; return x; }
int g(int & x) { std::cout << "g(" << x << ")\n"; return ++x; }
int main() { int x = 2;
// app(_, 3)(f);
boost::bind( boost::apply<int>(), _1, 3 )(f);
// app(_, x)(g);
boost::bind( boost::apply<int>(), _1, x )(g); boost::bind( boost::apply<int>(), _1, boost::ref(x) )(g); }
You are saying that in the general case we can't decide between the last two lines, so we shouldn't support references.
In a nutshell, yes.
But I'm not sure that this is true. It seems to me that the rule is that I should use ref(x) if my x will outlive the function object, as in the above, and a plain x otherwise, and it will "just work".
This is not the rule I desire (though it is one possible way to go). I don't like this rule because it is deciding "whether to reference or not" based on the argument, rather than on the function. That is, in the case of app(_, x)(f); I don't want to pass "x" by reference simply because it appears be be a non-transient object with sufficient lifetime. "f" doesn't need a reference, so I shouldn't be creating one. In any case, the question of "if my x will outlive the function object" is non-trivial. Consider // assume h is a functoid with signature int h(int&,int) // assume l is a list<int> { int x = 1; l = map( h(x), l ); // note that "h(x)" means "h(x,_)" } Does "x" outlive the function object? Is it reasonable to pass "x" by reference? The answer to both is no. Functional programming idioms often create less-than-obvious lifetime issues. In the case above, the function object outlives "x", because "l" is a lazy list and it stores the function object so that list elements can later be computed on-demand.
boost::lambda's "solution" is to always take reference parameters; this is why we have
(_1 + _2)( 5, 7 ) // no, not 12--it's illegal
No, not correct. In the bind equivalent to app(_, x)(f), x is always copied by default. It's f that is passed by reference.
Right, sorry; I was unclear. The function objects created via lambda expressions always take non-const reference parameters. In contrast, FC++ function objects always take const reference parameters. (And, in both libraries, partial application makes a copy of the bound arguments.) (Is this right?) -- -Brian McNamara (lorgon@cc.gatech.edu)