|
Boost : |
From: Peter Dimov (pdimov_at_[hidden])
Date: 2004-02-20 08:38:02
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.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk