
Brian McNamara wrote: [...]
Passing a non-ref-wrapped argument to a functoid that expects that argument by-reference is a compile-time error.
[...]
Here's what we end up with
int x; app(_,3)(f); // fine (works now) app(_,x)(f); // fine (works now) app(_,3)(g); // compile-time error app(_,x)(g); // compile-time error // (1) app(_,ref(x))(g); // works
f(3); // fine (works now) f(x); // fine (works now) g(3); // compile-time error g(x); // compile-time error // (2) g(ref(x)); // works
I think this is a system which is self-consistent, allows for references, does not have different behavior depending upon whether first-order or higher-order functions are used, and works with the design constraint (DC) mentioned at the top of this message.
There are two main ways this works different from boost::lambda. At (1) (and maybe also the line above), boost would create a copy and then modify the copy. In the system I envision, this would be an error.
There are some interesting subtleties here. In Lambda (and an earlier version of Bind), (1) will create a _const_ copy and then fail to call g. The current Bind, however, behaves as you describe since it follows the TR1 proposal more closely. The TR1 bind specification says that "if the function application is made through a cv-qualified reference to, or a copy of, the function object, the same cv qualifiers are applied to f and aN." In our case, since (the equivalent of) app(_, x) is non-const, its state, which includes the copy of x, can be changed. But if you pass app(_, x) by const reference to some algorithm, app(_, x)(g) will fail.
(This is the desirable behavior, IMO.)
Maybe. I'd be interested in some rationale, though. :-)