Board index » cppbuilder » Re: BDS2006: Variant-var as reference parameter in a method assigned to AnsiString-var

Re: BDS2006: Variant-var as reference parameter in a method assigned to AnsiString-var


2008-02-18 02:18:03 AM
cppbuilder3
"Alan Bellingham" < XXXX@XXXXX.COM >wrote in message
Quote
On the other hand, when someone wanders in with an outdated version
themselves, it helps if someone can work out what's going on.
I have BCB5, BCB6, BDS2006, and RAD2007 installed (between two computers).
If only I hadn't sat on my BCB4 disk I'd have that installed too. Having
different compiler versions certainly helps my newsgroup answers to be more
correct. Now, if I had just chimed in before you and Jason got going.
Instead, you two seem to have started off on the wrong foot.
Clayton
 
 

Re:Re: BDS2006: Variant-var as reference parameter in a method assigned to AnsiString-var

"Alan Bellingham" < XXXX@XXXXX.COM >wrote:
Quote
I have a relatively shiny copy of VC2005, which is much nicer to
develop with for what I'm doing.
I was in the same boat for a while (I considered switching to BCB because I
didn't like the generated code that VC gives you when you make a Windows
Forms application). Make sure you get the newest Platform SDK, it ships with
the new compiler :-P .
"Alan Bellingham" < XXXX@XXXXX.COM >wrote in message
Quote
>To be fair, it also behaves as Alan
>describes with 2006 which the OP is using.

Does it, indeed?

Any idea whether it has been fixed since, or is it still there in BCB
2007?
It's not very polite to comment on somebody's post without reading the whole
thing, you know -- reread that last reply I made to you. 5.92 and 5.93 ship
with BCB 2007 (5.93 is after the December update). Anyways you already
answered this question for yourself in a previous comment:
"Alan Bellingham" < XXXX@XXXXX.COM >wrote in message
Quote
I'm happy for you that the current compiler has fixed this bug
If I purchase BCB2007, the first thing I am going to write will be an
application to scan the Borland newsgroups and generate random Alan
Bellingham quotes. I'll have to learn more about natural language processing
so I can make it analyze the quotes and give you a little slider that
adjusts the weasel-factor of what you get back.
"Alan Bellingham" < XXXX@XXXXX.COM >wrote:
Quote
those of us who've been on the group for a while
"Alan Bellingham" < XXXX@XXXXX.COM >wrote:
[1] a brilliant footnote
"Alan Bellingham" < XXXX@XXXXX.COM >wrote:
Does it, indeed?
"Alan Bellingham" < XXXX@XXXXX.COM >wrote:
Oh carry on, you'll make me feel ancient yet.
"Alan Bellingham" < XXXX@XXXXX.COM >wrote:
People
who've only seen the newer compilers don't realise just how
'interesting' some of the older compiler quirks could be.
Hours of fun, from that loveable Alan.
 

Re:Re: BDS2006: Variant-var as reference parameter in a method assigned to AnsiString-var

Jason Cipriani < XXXX@XXXXX.COM >wrote:
Quote
[...] If your function must take a
reference and you don't care about any changes it makes to it's parameter,
you can also do this:

void Method (Variant &var) {
}

{
AnsiString s;
Method(Variant(s));
}
Except that this, too, attempts to bind a temporary to
a non-const reference and thus shouldn't compile either.
Quote
[...]
Jason
Schobi
--
XXXX@XXXXX.COM is never read
I'm HSchober at gmx dot de
"The trouble with being a god is that you've got
no one to pray to." Terry Pratchett
 

{smallsort}

Re:Re: BDS2006: Variant-var as reference parameter in a method assigned to AnsiString-var

Hi Hendrik
Quote
"The trouble with being a god is that you've got
no one to pray to." Terry Pratchett
unless there is more then one god ;-)
Kind regards
Asger
 

Re:Re: BDS2006: Variant-var as reference parameter in a method assigned to AnsiString-var

"Hendrik Schober" < XXXX@XXXXX.COM >wrote in message
Quote
Jason Cipriani < XXXX@XXXXX.COM >wrote:
>{
>AnsiString s;
>Method(Variant(s));
>}

Except that this, too, attempts to bind a temporary to
a non-const reference and thus shouldn't compile either.
Actually, this is OK. What it does is:
Construct a new Variant from s (using Variant::Variant(const AnsiString &)
or similar). Pass that to Method(). It's a perfectly valid object,
explicitly constructed by you. Method() does it's thing, possibly modifying
the temporary, and when it returns and the temporary goes out of scope, the
temporary is deleted. It works for two reasons:
1) The temporary is valid during the entire call to Method().
2) It was explicitly constructed by you; therefore the compiler doesn't have
to make any guesses about what to do.
Somebody correct me if I'm wrong, but I'm not even actually sure if you'd
call that a "temporary". Aren't "temporaries" only objects that are
implicitly created by the compiler, behind the scenes?
By the way, this also works:
{
AnsiString s;
Method((Variant)s);
}
Same deal. The Variant() you construct there is in scope the entire call to
Method(). However, the reason that works is not why you think it is. In that
case ("(Variant)s"), the *only* reason it works is because AnsiString
does -not- have a casting operator to a Variant, so the compiler uses the
Variant constructor instead! If AnsiString has a Variant casting operator
but Variant did not have an AnsiString constructor, neither of those would
compile!
Remember: You can pass any l-value to a function that takes things by
reference. Consider the following code:
struct B;
struct A {
A (const B&) { }
};
struct B {
};
void function (A &) {
}
int main (int, char **) {
B b;
function(A(b));
function((A)b);
return 0;
}
In both cases, the compiler uses that A(const &B) constructor for "A(b)" and
"(A)b", because this is the only way it can perform that conversion. In this
case, both are equivalent to "A(b)". A(b) is an l-value -- i.e. the
following code is valid:
B b;
A(b) = something_else;
It is equivalent to:
A(B()).operator = (something_else);
Nothing wrong with that. Now consider this:
struct B;
struct A {
};
struct B {
operator A () { }
};
void function (A &) {
}
int main (int, char **) {
B b;
function(A(b));
function((A)b);
return 0;
}
This does not compile. In this case, the only way to perform the conversions
A(b) and (A)b is through B's casting operator. So both are like "(A)b". This
is not an l-value -- and there is a hidden temporary being created here --
that is, the A object that is implicitly copied when B's A casting operator
returns. The following code is not allowed:
(A)b = something_else;
Just as you can't do this:
int a;
(double)a = 2.0;
Now, as a third weird example, this is what I had posted in an earlier post.
Consider this, which is about the same as above but the casting operator
returns a reference instead of a copied object:
struct B;
struct A {
};
struct B {
operator A& () {
static A dummy;
return dummy;
}
};
void function (A &) {
}
int main (int, char **) {
B b;
function(A(b));
function((A)b);
return 0;
}
This also works. The reason that this works (where the "A" cast does not
work) is that in this case, (A)b is an l-value. In fact, it eventually
evaluates to "dummy". No implicit objects are created behind the scenes --
no copies are made, no implicit casts.
Hopefully that made sense. "(Variant)s" is legal in that case only because
Variant has an AnsiString constructor, the compiler uses it, and the
anonymous Variant() you *explicitly* create is valid and OK to pass by
reference. You know, the more I think about it, the more I'm pretty sure
that "temporaries" are things the compiler implicitly creates, rather than
things you explicitly tell it to create.
Jason
 

Re:Re: BDS2006: Variant-var as reference parameter in a method assigned to AnsiString-var

"Jason Cipriani" < XXXX@XXXXX.COM >wrote in message
Quote
"Hendrik Schober" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...
>Jason Cipriani < XXXX@XXXXX.COM >wrote:
>>{
>>AnsiString s;
>>Method(Variant(s));
>>}
>
>Except that this, too, attempts to bind a temporary to
>a non-const reference and thus shouldn't compile either.

Actually, this is OK.
P.S. I did not actually realize until now that the *reason* that was OK was
as deep as it was. Otherwise I would have said it. Learn something new every
day, I guess -- I was surprised (although in thinking about it it seems
really reasonable) that the presence of a casting operator made that not
work. Does anybody know what the precedence order is for ways the compiler
will try to convert one object to another? There's constructors,
constructors that take references, const references, casting operators that
return objects, references to objects, are const or non-const... is that
compiler-defined?
 

Re:Re: BDS2006: Variant-var as reference parameter in a method assigned to AnsiString-var

Asger Joergensen < XXXX@XXXXX.COM >wrote:
Quote
Hi Hendrik

>"The trouble with being a god is that you've got
>no one to pray to." Terry Pratchett

unless there is more then one god ;-)
Ah, you don't know Pratchett!
On his diskworld, there's very many gods. For a starter
on the subject, I suggest "Small Gods". (That one got
me hooked, BTW.)
Quote
Kind regards
Asger
Schobi
--
XXXX@XXXXX.COM is never read
I'm HSchober at gmx dot de
"The trouble with being a god is that you've got
no one to pray to." Terry Pratchett
 

Re:Re: BDS2006: Variant-var as reference parameter in a method assigned to AnsiString-var

Jason Cipriani < XXXX@XXXXX.COM >wrote:
Quote
"Hendrik Schober" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...
>Jason Cipriani < XXXX@XXXXX.COM >wrote:
>>{
>>AnsiString s;
>>Method(Variant(s));
>>}
>
>Except that this, too, attempts to bind a temporary to
>a non-const reference and thus shouldn't compile either.

Actually, this is OK. What it does is:

Construct a new Variant from s (using Variant::Variant(const AnsiString &)
or similar). Pass that to Method(). It's a perfectly valid object,
explicitly constructed by you. Method() does it's thing, possibly modifying
the temporary, and when it returns and the temporary goes out of scope, the
temporary is deleted.
I think I know what it does. It might even work using
BCC. But I still don't think it should.
Look at this code:
struct X {};
struct Y {
Y(const X&) {}
};
void f(Y&) {}
void g(const Y&) {}
int main()
{
X x;
f( x );
f( Y(x) );
f( (Y)x );
g( x );
g( Y(x) );
g( (Y)x );
return 0;
}
Comeau Online (www.comeaucomputing.com/tryitout/)
has this to say to it:
Comeau C/C++ 4.3.9 (Mar 27 2007 17:24:47) for ONLINE_EVALUATION_BETA1
Copyright 1988-2007 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions
"ComeauTest.c", line 13: error: a reference of type "Y &" (not const-
qualified) cannot be initialized with a value of type "X"
f( x );
^
"ComeauTest.c", line 14: error: initial value of reference to non-const
must be anlvalue
f( Y(x) );
^
"ComeauTest.c", line 15: error: initial value of reference to non-const
must be an lvalue
f( (Y)x );
^
3 errors detected in the compilation of "ComeauTest.c".
There's little to add to this.
Quote
[...]
Somebody correct me if I'm wrong, but I'm not even actually sure if you'd
call that a "temporary". Aren't "temporaries" only objects that are
implicitly created by the compiler, behind the scenes?
No. I don't know an official definition off-hand, but
I'd say a temporary object is one that has no name and
a lifetime that ends at the end of the full expression
it was created in (unless it's bound to a const ref...)
Quote
[...]
Jason
Schobi
--
XXXX@XXXXX.COM is never read
I'm HSchober at gmx dot de
"The trouble with being a god is that you've got
no one to pray to." Terry Pratchett
 

Re:Re: BDS2006: Variant-var as reference parameter in a method assigned to AnsiString-var

"Hendrik Schober" < XXXX@XXXXX.COM >wrote in message
Quote
I think I know what it does. It might even work using
BCC. But I still don't think it should.
Hmm; well, I don't know what the standard says about it. Do you? If you are
talking about personal opinion, I guess it just depends on how you look at
it. In your example, like you, I think "f(x);" should not compile for the
same reason that you aren't allowed to, say, assign a void* to a char*
without an explicit cast: It's nice of the compiler to make sure that I
really mean to do what I'm doing and that it's not a mistake. But in the
case of Y(x) and (Y)x, I am explicitly stating what I want to happen -- and
I mean it.
Also, I think Comeau is the one that might be screwed up here. A bold claim,
I know. But check this out. Look at your errors:
Quote
"ComeauTest.c", line 14: error: initial value of reference to non-const
must be anlvalue
f( Y(x) );
^

"ComeauTest.c", line 15: error: initial value of reference to non-const
must be an lvalue
f( (Y)x );
^
Initial value of reference to non-const must be an l-value. This is
reasonable, of course. But it appears that Comeau is a little inconsistent
about what it thinks an l-value is, as it compiles the following code with
no errors or warnings, in strict mode:
struct X {};
struct Y {
Y(void) {}
Y(const X&) {}
};
int main (int, char **) {
X x;
Y assignme;
(Y(x)) = assignme;
((Y)x) = assignme;
return 0;
}
This is the result that I expected -- the result you got is *not* the result
I expected. An l-value is something that can appear on the left side of an
equal sign. Y(x) and (Y)x are both l-values.
Comeau gets even more mysterious. Remember what I said before about how (Y)x
only happens to be an l-value because the Y(const X&) constructor was the
only way to do the conversion? And if you had no Y(const X&) constructor but
you gave X a Y cast operator, then it would not work? Well, I think that I
might have been wrong about that as a general statement. I observed that
behavior in the Borland compiler and I believe in GCC as well (although now
I don't remember and haven't retested it). But Comeau contradicts what I
said, as the following code also compiles:
struct Y {
Y(void) {}
};
struct X {
operator Y (void) { return Y(); }
};
int main (int, char **) {
X x;
Y assignme;
(Y(x)) = assignme;
((Y)x) = assignme;
return 0;
}
In this case there is no way to construct a Y from an X, but you can cast an
X to a Y. Comeau still treats both Y(x) and (Y)x as l-values here, using
(I'm assuming) the casting operator for both statements (just as "double(n)"
and "(double)n" are both casts).
I'm not sure what to think about it all. I might be missing something, but I
don't think I am -- it definitely appears that Comeau is being inconsistent
about what it treats as "l-values".
My *theory* about Comeau here (based on nothing except that it's a possible
explanation that leads to this effect) is that since not allowing you to
pass these kinds of temporaries (using the broader definition) as non-const
reference parameters to functions is kind of an arbitrary rule (i.e. there
is no reason to disallow it other than protecting a programmer from
himself), they had to code in some compiler rule to explicitly check for
this situation and disallow it. They reason they had to explicitly check for
this particular situation is because Y(x) and (Y)x (with the constructor --
I can't explain why it works with just a casting operator) are, in fact,
l-values. I don't know why they disallow this -- is it part of the standard
or do they have their own reasons? In any case, either Comeau is wrong about
something, or the error message you got from Comeau is not correct, and they
mean something else besides "l-values".
Jason
 

Re:Re: BDS2006: Variant-var as reference parameter in a method assigned to AnsiString-var

"Jason Cipriani" < XXXX@XXXXX.COM >wrote in message
Quote
(Y(x)) = assignme;
By the way (I know, I add too many "P.S." posts... sorry), it's not quite
related but the reason I have (Y(x)) enclosed in parenthesis is because if I
just do this:
Y(x) = assignme;
Comeau complains that 'x' was already declared. The reason is because it
thinks I mean this:
Y x = assignme;
In other words, that I'm declaring a variable 'x' of type Y and initially
assigning it to 'assignme'. You need the parentheses to clear it up. That's
something I never knew. I did not try it with other compilers.
Jason
 

Re:Re: BDS2006: Variant-var as reference parameter in a method assigned to AnsiString-var

If you are considering replying to my post, I wouldn't think too hard about
it just yet. Instead, follow this thread on comp.lang.c++:
groups.google.com/group/comp.lang.c++/browse_thread/thread/dec8c35806b61a7d
I'm trying to clear stuff up there. So far I've learned/confirmed:
* That broad definition of "temporary object" is indeed the correct one.
* Contrary to what I thought, just because something can appear on the left
side of an = sign doesn't necessarily mean it's an l-value. I -think-. And
so...
* ...Comeau is correct, it's my idea of an l-value that is wrong. Borland's
C++ compiler should not be accepting the code that binds a temporary to a
non-const reference by using the temporary's conversion constructor (BCC
rejects the implicit conversion and the conversion when only a cast is
available, but does not reject the conversion using a constructor -- it
should reject all 3).
Jason
 

Re:Re: BDS2006: Variant-var as reference parameter in a method assigned to AnsiString-var

Jason Cipriani wrote:
Quote
Also, I think Comeau is the one that might be screwed up here. A bold claim,
I know. But check this out. Look at your errors:

>"ComeauTest.c", line 14: error: initial value of reference to non-const
>must be anlvalue
>f( Y(x) );
>^
From the standard:
3.10 Lvalues and rvalues [basic.lval]
1 Every expression is either an lvalue or an rvalue.
...
5 The result of calling a function that does not return a reference is
an rvalue. ...
6 An expression which holds a temporary object resulting from a cast
to a nonreference type is an rvalue (this includes the explicit
creation of an object using functional notation.
So I think Comeau is correct here (as in nearly all cases).
Quote
(Y(x)) = assignme;
((Y)x) = assignme;
Perhaps one of the real C++ standard experts can step in here, but I
see nothing in the standard which allows this.
- Leo
 

Re:Re: BDS2006: Variant-var as reference parameter in a method assigned to AnsiString-var

Jason Cipriani wrote:
Quote
*Contrary to what I thought, just because something can appear on
the left side of an = sign doesn't necessarily mean it's an l-value.
I -think-.
From the standard:
5.17 Assignment operators
1 There are several assignment operators, all of which group
right-to-left. All require a modifiable lvalue as their left
operand...
- Leo
 

Re:Re: BDS2006: Variant-var as reference parameter in a method assigned to AnsiString-var

Leo Siefert wrote:
Quote
From the standard:
BTW - From what I can see the standard does not require a diagnostic
for this, so the Comeau compiler is technically within its rights not
to issue one.
Possibly these lines are simply ignored since logically an assignment
to a temporary would be expected to have no effect.
- Leo
 

Re:Re: BDS2006: Variant-var as reference parameter in a method assigned to AnsiString-var

"Udo Weik" < XXXX@XXXXX.COM >wrote in message
Quote
When I now call that Method with an AnsiString-var like
AnsiString AnsiStringVar ;
Method( AnsiStringVar ) ;
AnsiStringVar is NULL. Why?
You are trying to pass an AnsiString reference where a Variant reference is
expected, so the compiler has to first construct a temporary Variant for the
actual method call. That temporary is NOT passed to the AnsiString
afterwards. In otherwards, the above code is functionally equivilent to the
following:
AnsiString AnsiStringVar;
Variant tempVar;
Method(tempVar);
// tempVar is NOT assigned to AnsiStringVar here!!!
Gambit