
Brian McNamara wrote:
Here's my rationale; tell me what you think:
If you have a reference parameter, it's because you want to have an effect on an argument. Examples are "in-out" or "out" parameters, where the parameter value is changed/assigned by the function so that the new value can be used by the caller.
As a result, passing a copy of the argument and having the function modify the copy (as in some cases in boost::lambda) means that the modification gets "lost". In the example
app(_,x)(g); // copy x, pass copy to g
"g" is oblivious to the fact that it's not being called as just
g(x);
Whatever side-effects "g" makes to its argument never make it back to the caller, since "app" is passing it a copy of "x".
With you so far, but...
The "lost" information probably indicates an error in the program.
... I don't accept this assertion. The experience with C++ before non-const references could not bind to temporaries indicated that this is typically just what the programmer intended. Contrary to your hunch, ...
(My hunch is that this is very rare; you don't typically "try to ignore" reference parameter modifications.)
... programmers do sometimes want to ignore reference parameter modifications. The reason for the "no non-const references to temporaries" rule is that implicit conversions often lead to errors of the form: void f(int & x); double y; f(y); where the programmer does not intend to throw away the result, since y is an lvalue. However, the double to int implicit conversion leads to a temporary being created, modified, and thrown away. If you try the equivalent example with boost::bind: #include <boost/bind.hpp> void f(int & x); int main() { double y = 0; boost::bind(f, y)(); } you'll receive a compile-time error. Here are some examples to illustrate why Boost.Bind is (supposed to be, as wel'll see later) cv-transparent: #include <boost/bind.hpp> #include <iostream> struct F { typedef void result_type; void operator()(int x) { std::cout << "F::operator()(" << x << ")\n"; } }; int main() { F f; f(1); boost::bind(f, 1)(); } Note that F::operator() is non-const. Expanded version: #include <boost/bind.hpp> #include <iostream> struct F { typedef void result_type; void operator()(char const * x) { std::cout << "F::operator()(" << x << ")\n"; } void operator()(char const * x) const { std::cout << "F::operator()(" << x << ") const\n"; } }; template<class F> void test(F f) { f("test"); } template<class F> void test2(F const & f) { f("test2"); } int main() { test( F() ); test2( F() ); test( boost::bind( F(), _1 ) ); test2( boost::bind( F(), _1 ) ); } This actually exposes a bug in boost::bind. Oops. ;-) Will fix.