
Brian McNamara wrote: [...]
Dealing with references is relatively straightforward for first-order functoids, but when you deal with higher-order ones, it quickly becomes hard (impossible?) to do the right thing. For example: suppose we want to write a functoid "app", such that
app( f, x ) == f(x)
Should the second parameter be "by value" or "by reference"? The "right answer", IMO, is that it depends on whether "f" takes its argument by value or reference. Except that this dependency now excludes many uses of app(), such as
app( _, 3 )
Even though the result of that may be later used in a context that should/would be legal, "right now" we don't know if we should be copying the 3 or trying to take a reference to it. Whichever choice we make, it might turn out to be the "wrong" choice later.
Taking the liberty to reorder:
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. 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".
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.