Yes, and I'm not sure what to do about it. In practice, it will
in fact always work as long as the function you call eventually
does make the lvalue to rvalue conversion, and use the value; it
will fail if the function takes the address of the reference,
and starts comparing addresses (since the address of the c
object will be different in different translation units). How
to formulate this distinction in standardese is not clear,
however, so the standard takes the easy way out: if there isn't
an immediate conversion, it's undefined behavior. (So:
int const c = 43 ;
inline void
f( std::vector< int >& dest )
{
int tmp = c ;
dest.push_back( tmp ) ;
}
is legal.)
In practice, I don't see how an implementation can actually make
this fail, and I tend to ignore the issue, at least in such
cases where it is clear that the called function will only use
the value (and the fact that the function takes a reference is
only because it is a template---had the function been written
exclusively for int, it would have used pass by value). But the
fact that I can't imagine an implementation in which it would
fail may just be due to a lack of imagination on my part. (If I
were writing a compiler, I'd try to arrange things so that as
many violations as possible of the one definition rule were
caught by the linker. But this one is difficult.)
Could you run that by me again? The compiler has never been
allowed to create a temporary when the initializer of a
reference (to const or not) is an lvalue. As far as I can see,
the wording for the case where the initializer of a reference is
an lvalue (and not a bit-field) is unchanged since C++98.
What may change things in some cases is the fact that there is
an overload of vector<>:
ush_back which takes an rvalue
reference. I don't think it's relevant here (but I haven't
really verified), because the int const should match the
push_back which takes the const lvalue reference, resulting in
exactly the same behavior as usual.
The old Fortran trick to "emulate" call be value. (In Fortran,
if you passed what would be an lvalue in C or C++, it could be
modified by the called function. If you passed what would be an
rvalue, no.) As I said, the more things change, the more they
remain the same.
I sort of prefer the named value, since it seems clearer. Sort
of---it's not immediately apparent in either case why you don't
use just c.
Again, I don't really see that point. A compiler is *not*
allowed to create a temporary when the initializer of a
reference is an lvalue. Ever. If I write something like:
int a ;
int const& b = a ;
I'm guaranteed that &b == &a, and that if I use b to initialize
other references, the referred to int has the lifetime of a,
even if b goes out of scope. (Not sure if the lifetime issue is
clear. Consider:
namespace { int i ; } ;
class C
{
public:
C( int const& init ) : myI( init ) {}
// ...
private:
int const& myI ;
} ;
C*
f()
{
int const& i1 = i ;
return new C( i1 ) ;
}
I'm guaranteed that I can use the returned C without problems;
that C::myI won't be a dangling reference. Which it would be if
I had written:
int const& i1 = i + 0 ;
return new C( i1 ) ;
.)