Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Isn't function resolution consistent?

Reply
Thread Tools

Isn't function resolution consistent?

 
 
DeMarcus
Guest
Posts: n/a
 
      04-28-2010
Paul Bibbings wrote:
> DeMarcus <(E-Mail Removed)> writes:
>
>>> So, you would have to adjust and not return a reference, say:
>>>
>>> A&& operator<<(A&&, const B&)
>>>
>>> But then, your chaining wouldn't work in the same way, and
>>>
>>> A() << aB << anotherB << yetAnotherB;
>>>
>>> would involve a succession of distinct temporary instances of A.
>>>

>> I solved it! I think. How about this in A.hpp?
>>
>> template<typename T>
>> inline A&& operator<<( A&& a, const T& t )
>> {
>> std::cout << "Delegating..." << std::endl;
>> return operator<<( a, t );
>> }

>
> Clearly you are avoiding infinite recursion here in the call to return
> operator<<( a, t ). How are you achieving that? What /other/
> definition of op<< are you using? The one defined in the class A? But
> that returns A&, doesn't it? And then that shouldn't bind to the return
> of A&& here.
>


I don't know how I achieve that. For that example I stripped everything
so I only have this one left (except for the delegator).

A& operator<<( A& a, const B& b )
{
std::cout << "Non-member Function" << std::endl;
return a;
}


Try this simple example that "worked" for me.

//B.hpp (with appropriate #ifndef B_HPP_)
class B
{
};
std:stream& operator<<( std:stream& s, const B& b );

// B.cpp
std:stream& operator<<( std:stream& s, const B& b )
{
return s << "B";
}

// main.cpp
#include "B.hpp"
#include <sstream>

void fnc( const std:stream& s )
{
std::cout << s.rdbuf() << std::endl;
}

template<typename T>
inline std:stream&& operator<<( std:stream&& s, const T& t )
{
return operator<<( s, t );
}

int main()
{
B b;
fnc( std::stringstream() << b );
}


> I might be getting a little lost here, so can I ask... Does your
> compiler compile this?:
>
> A&& operator<<(A&& a, const B&)
> {
> return a;
> }
>
> (Note: it *shouldn't*)
>


If I put the definition in B.cpp it compiles but if I put everything in
B.hpp it doesn't compile with the following error.

multiple definition of 'operator<<(S&&, V const&)'

 
Reply With Quote
 
 
 
 
Paul Bibbings
Guest
Posts: n/a
 
      04-28-2010
DeMarcus <(E-Mail Removed)> writes:

I will split my response into two separate posts, for clarity of
issues. Here we'll look at the following.
>
>> I might be getting a little lost here, so can I ask... Does your
>> compiler compile this?:
>>
>> A&& operator<<(A&& a, const B&)
>> {
>> return a;
>> }
>>
>> (Note: it *shouldn't*)
>>

>
> If I put the definition in B.cpp it compiles but if I put everything
> in B.hpp it doesn't compile with the following error.
>
> multiple definition of 'operator<<(S&&, V const&)'


This illustrates that your compiler (gcc-4.4.1) is implementing rvalue
references according to an early specification that has now been
superceded. At present, I don't have all the necessary references to
hand, but there was a significant change in the specification, and one
key part of the change was that, whereas originally it was allowed for
rvalue references to bind to lvalues, now it is not. If gcc-4.4.1 will
compile the above code without requiring:

return std::move(a)

to convert to an rvalue reference, then it is out of date, and
discussion about whether your code (and the model behind it) is valid
is, essentially, not possible on this basis.

To add another point, another change was that, in the body of a function
having a *named* parameter that is an rvalue reference, within that body
it would behave as an lvalue on account of it being named. This is why
std::move(a) is required here, even though we have passed the function
an rvalue reference. Without it, in the bare statement:

return a;

a is an *lvalue* (i.e., no longer an rvalue), and by the first point will
not bind to the return type of A&&.

I would suggest an upgrade, if that is possible. gcc-4.5.0 is available
and handles the changed specification correctly (AFAICT), as does
gcc-4.4.3, I believe.

Regards

Paul Bibbings
 
Reply With Quote
 
 
 
 
Paul Bibbings
Guest
Posts: n/a
 
      04-28-2010
DeMarcus <(E-Mail Removed)> writes:

> Paul Bibbings wrote:
>> DeMarcus <(E-Mail Removed)> writes:
>>> I solved it! I think. How about this in A.hpp?
>>>
>>> template<typename T>
>>> inline A&& operator<<( A&& a, const T& t )
>>> {
>>> std::cout << "Delegating..." << std::endl;
>>> return operator<<( a, t );
>>> }

>>
>> Clearly you are avoiding infinite recursion here in the call to return
>> operator<<( a, t ). How are you achieving that? What /other/
>> definition of op<< are you using? The one defined in the class A? But
>> that returns A&, doesn't it? And then that shouldn't bind to the return
>> of A&& here.
>>

>
> I don't know how I achieve that. For that example I stripped
> everything so I only have this one left (except for the delegator).
>
> A& operator<<( A& a, const B& b )
> {
> std::cout << "Non-member Function" << std::endl;
> return a;
> }
>
>
> Try this simple example that "worked" for me.
>


How can the following work, since you are using std:stream without
including the appropriate header in B.hpp?

> //B.hpp (with appropriate #ifndef B_HPP_)
> class B
> {
> };
> std:stream& operator<<( std:stream& s, const B& b );
>
> // B.cpp
> std:stream& operator<<( std:stream& s, const B& b )
> {
> return s << "B";
> }
>


How can the following work, since you do not include the appropriate
header to make std::cout, std::endl, etc., available?

> // main.cpp
> #include "B.hpp"
> #include <sstream>
>
> void fnc( const std:stream& s )
> {
> std::cout << s.rdbuf() << std::endl;
> }
>
> template<typename T>
> inline std:stream&& operator<<( std:stream&& s, const T& t )
> {
> return operator<<( s, t );
> }
>
> int main()
> {
> B b;
> fnc( std::stringstream() << b );
> }
>


There are other headers missing too. (This is what I was trying to
convey in another post. It is _crucial_ that you post the *exact* code
that you have compiled, or else how can I be sure that my `guesses' at
what is missing don't introduce further problems masking the ones you
are experiencing? If your code needs "appropriate #ifndef" include
guards, put them in!)

However...

As I've mentioned in another post, gcc-4.4.1 is an outdated
implementation with regards to rvalue references and how these are
handled, effectively rendering it worthless (and, indeed, misleading) in
this regard. To illustrate, whilst I can get the code (suitably
corrected) to compile and produce the `expected' results in gcc-4.4.1,
it is nevertheless incorrect according to the specification as it now
stands.

18:54:55 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/CLCPP/consistent_resolution/partII
$i686-pc-cygwin-g++-4.5.0 -std=c++0x -o B main.cpp B.cpp
main.cpp: In function ¡®std:stream&& operator<<(std:stream&&,
const T&) [with T = B, std:stream = std::basic_ostream<char>]¡¯:
main.cpp:21:32: instantiated from here
main.cpp:15:28: error: invalid initialization of reference of type
¡®std:stream&&¡¯ from expression of type ¡®std:stream¡¯

In short, experimenting with rvalue references using gcc-4.4.1 is simply
a no-starter, unfortunately. Effectively you are writing code to follow
an implementation that was never ratified as standard, and nor will it
be, rendering it a worthwhile exercise only on historical grounds, and
nothing else.

HTH

Regards

Paul Bibbings

 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      04-28-2010
On Apr 28, 7:35 am, DeMarcus <(E-Mail Removed)> wrote:
> Paul Bibbings wrote:


[...]
> >> //A.hpp (with appropriate #ifndef A_HPP_)
> >> class A
> >> {
> >> public:


> >> template<typename T>
> >> A& operator<<( const T& t )
> >> {
> >> std::cout << "Function Template" << std::endl;
> >> return *this;
> >> }
> >> };


> >> // B.hpp (with appropriate #ifndef B_HPP_)
> >> class A;
> >> class B
> >> {
> >> };
> >> A& operator<<( A& a, const B& b );


> >> // B.cpp
> >> #include "B.hpp"
> >> #include "A.hpp"
> >> A& operator<<( A& a, const B& b )
> >> {
> >> std::cout << "Non-member Function" << std::endl;
> >> return a;
> >> }


[...]
> Yes, but now comes the strange part. Let's change main.cpp slightly to
> the following.


> // file: main.cpp
> #include "A.hpp"
> #include "B.hpp"


> void fnc( const A& a )
> {
> }


> int main()
> {
> B b;
> fnc( A() << b );
> }


> Now it prints "Function Template". Why?


Because that's the only function it can legally call. Your free
operator<< takes a non-const reference to A, and you can't
initialize a non-const reference with a temporary.

--
James Kanze
 
Reply With Quote
 
DeMarcus
Guest
Posts: n/a
 
      04-29-2010
Paul Bibbings wrote:
> DeMarcus <(E-Mail Removed)> writes:
>
> I will split my response into two separate posts, for clarity of
> issues. Here we'll look at the following.
>>> I might be getting a little lost here, so can I ask... Does your
>>> compiler compile this?:
>>>
>>> A&& operator<<(A&& a, const B&)
>>> {
>>> return a;
>>> }
>>>
>>> (Note: it *shouldn't*)
>>>

>> If I put the definition in B.cpp it compiles but if I put everything
>> in B.hpp it doesn't compile with the following error.
>>
>> multiple definition of 'operator<<(S&&, V const&)'

>
> This illustrates that your compiler (gcc-4.4.1) is implementing rvalue
> references according to an early specification that has now been
> superceded. At present, I don't have all the necessary references to
> hand, but there was a significant change in the specification, and one
> key part of the change was that, whereas originally it was allowed for
> rvalue references to bind to lvalues, now it is not. If gcc-4.4.1 will
> compile the above code without requiring:
>
> return std::move(a)
>
> to convert to an rvalue reference, then it is out of date, and
> discussion about whether your code (and the model behind it) is valid
> is, essentially, not possible on this basis.
>
> To add another point, another change was that, in the body of a function
> having a *named* parameter that is an rvalue reference, within that body
> it would behave as an lvalue on account of it being named. This is why
> std::move(a) is required here, even though we have passed the function
> an rvalue reference. Without it, in the bare statement:
>
> return a;
>
> a is an *lvalue* (i.e., no longer an rvalue), and by the first point will
> not bind to the return type of A&&.
>
> I would suggest an upgrade, if that is possible. gcc-4.5.0 is available
> and handles the changed specification correctly (AFAICT), as does
> gcc-4.4.3, I believe.
>


Now, I've upgraded to 4.5.0 and, as you say, get following error:

error: invalid initialization of reference of type 'std:stream&&' from
expression of type 'std:stream'

I'm trying to understand the rvalue reference better. Would my delegator
template work?

template<typename T>
inline std:stream&& operator<<( std:stream&& s, const T& t )
{
return std::move( operator<<( s, t ) );
}

It compiles and runs under gcc 4.5.0, but there are two things that I
can't calculate in my head:

1. Is this a valid treatment of the ostream s? I mean, I'm not allowed
to provide a temporary to a non-const ref, but here it apparently works.
Would this be the proper solution?

template<typename T>
inline std:stream&& operator<<( std:stream&& s, const T& t )
{
std:stream s2( s ); // if future ostreams get move semantics
operator<<( s2, t );
return std::move( s2 );
}


2. Why don't I get an infinite recursion as you suggested in an earlier
post? I tried to clarify for the compiler which function I was looking
for with following.

template<typename T>
inline std:stream&& operator<<( std:stream&& s, const T& t )
{
return std::move( operator<< <S&, const T&>( s, t ) );
}

but got

error: no matching function for call to 'operator<<(std:stream&, const
B&)'

That is strange since that function does exist.

How do I convert a SomeClass&& to a SomeClass& ? It's not possible
unless SomeClass has move semantics, right?

 
Reply With Quote
 
Paul Bibbings
Guest
Posts: n/a
 
      04-29-2010
DeMarcus <(E-Mail Removed)> writes:

> Now, I've upgraded to 4.5.0 and, as you say, get following error:
>
> error: invalid initialization of reference of type 'std:stream&&'
> from expression of type 'std:stream'
>
> I'm trying to understand the rvalue reference better. Would my
> delegator template work?
>
> template<typename T>
> inline std:stream&& operator<<( std:stream&& s, const T& t )
> {
> return std::move( operator<<( s, t ) );
> }


I'm getting a little lost here. Every now and then you switch
(seemingly randomly) between examples that use what I have supposed is
your custom stream, class A, and then similar examples using
std:stream&(&), as here. For example, in an earlier post you
presented the following as your `delegator'.

>> I solved it! I think. How about this in A.hpp?
>>
>> template<typename T>
>> inline A&& operator<<( A&& a, const T& t )
>> {
>> std::cout << "Delegating..." << std::endl;
>> return operator<<( a, t );
>> }


Since, at each change, you present only snippets of code, it is very
important, in order to maintain context in my own mind, that I can make
assumptions about what I have seen already. Effectively, I am forced to
ask: "So, which /is/ your delegator?"

I say this because I think it makes a difference to this whole
discussion whether we are talking about some custom stream that you are
building or the std:stream. You seem intent on wanting to make
copious use of temporary instances of your stream class and pass these
around using rvalue references. That is fine, but I certainly wouldn't
want to use this method for std:stream. The reason being that, in
your own type, you are able to support your requirements by adjusting
how you implement your type. std:stream, on the other hand, is not
necessarily - actually, almost certainly not - implemented to fit in
well with your intensions.

>
> It compiles and runs under gcc 4.5.0, but there are two things that I
> can't calculate in my head:
>
> 1. Is this a valid treatment of the ostream s? I mean, I'm not allowed
> to provide a temporary to a non-const ref, but here it apparently
> works. Would this be the proper solution?


What is it that leads you to want to pass around temporary objects of
class std:stream in the first place? This is not how it is
conventionally done. Again, I might ask the same question of the
design of your custom stream class. Stream class are surely not cheap
to copy, and perhaps not even that cheap to move.

Overall, I can't help thinking that all your problems, or issues, would
simply disappear if you gave up wanting to use A() << b. Certainly I
have not yet, in this discussion, been able to gain a sense of its
purpose or value.

> template<typename T>
> inline std:stream&& operator<<( std:stream&& s, const T& t )
> {
> std:stream s2( s ); // if future ostreams get move semantics
> operator<<( s2, t );
> return std::move( s2 );
> }
>
>
> 2. Why don't I get an infinite recursion as you suggested in an
> earlier post? I tried to clarify for the compiler which function I was
> looking for with following.


In the body of the op<< function above, the rvalue reference parameter s
behaves as an lvalue. (This was one of the key changes to the current
implementation, IIUC). Thus, it's presence in the return statement

return operator<<( a, t );

will select an overload that accepts an lvalue as its first argument, if
one is available (as, I would suggest, there clearly is).

>
> template<typename T>
> inline std:stream&& operator<<( std:stream&& s, const T& t )
> {
> return std::move( operator<< <S&, const T&>( s, t ) );
> } ^

|
What is `S' here ------------------
>
> but got
>
> error: no matching function for call to 'operator<<(std:stream&,
> const B&)'
>
> That is strange since that function does exist.


Again, a *complete* compilable example would be necessary here in order
to permit me to comment on this.
>
> How do I convert a SomeClass&& to a SomeClass& ? It's not possible
> unless SomeClass has move semantics, right?


Under what circumstances would you want to do this, given the
fundamental difference between rvalue references (as, effectively,
temporary objects) and lvalues (as named regions of addressable
object storage)?

Regards

Paul Bibbings
 
Reply With Quote
 
DeMarcus
Guest
Posts: n/a
 
      04-29-2010
Paul Bibbings wrote:
> DeMarcus <(E-Mail Removed)> writes:
>
>> Now, I've upgraded to 4.5.0 and, as you say, get following error:
>>
>> error: invalid initialization of reference of type 'std:stream&&'
>> from expression of type 'std:stream'
>>
>> I'm trying to understand the rvalue reference better. Would my
>> delegator template work?
>>
>> template<typename T>
>> inline std:stream&& operator<<( std:stream&& s, const T& t )
>> {
>> return std::move( operator<<( s, t ) );
>> }

>
> I'm getting a little lost here. Every now and then you switch
> (seemingly randomly) between examples that use what I have supposed is
> your custom stream, class A, and then similar examples using
> std:stream&(&), as here. For example, in an earlier post you
> presented the following as your `delegator'.
>
>>> I solved it! I think. How about this in A.hpp?
>>>
>>> template<typename T>
>>> inline A&& operator<<( A&& a, const T& t )
>>> {
>>> std::cout << "Delegating..." << std::endl;
>>> return operator<<( a, t );
>>> }

>
> Since, at each change, you present only snippets of code, it is very
> important, in order to maintain context in my own mind, that I can make
> assumptions about what I have seen already. Effectively, I am forced to
> ask: "So, which /is/ your delegator?"
>


The final one is this for sure.

template<typename T>
inline A&& operator<<( A&& a, const T& t )
{
std::cout << "Delegating..." << std::endl;
return std::move( operator<<( a, t ) );
}

I will be able to do modifications to the stream-like A.


>> It compiles and runs under gcc 4.5.0, but there are two things that I
>> can't calculate in my head:
>>
>> 1. Is this a valid treatment of the ostream s? I mean, I'm not allowed
>> to provide a temporary to a non-const ref, but here it apparently
>> works. Would this be the proper solution?

>
> What is it that leads you to want to pass around temporary objects of
> class std:stream in the first place? This is not how it is
> conventionally done. Again, I might ask the same question of the
> design of your custom stream class. Stream class are surely not cheap
> to copy, and perhaps not even that cheap to move.
>


I definitely want to avoid a copy of A. I can live with one construction
of A though.

If found some code on internet from a guy doing similar things as I.

http://stackoverflow.com/questions/1...return-problem


> Overall, I can't help thinking that all your problems, or issues, would
> simply disappear if you gave up wanting to use A() << b. Certainly I
> have not yet, in this discussion, been able to gain a sense of its
> purpose or value.
>


It provides lazy evaluation of the log text which is important if you
want to switch the language, format and/or destinations in run-time. A
possible scenario could be if you want to send the same log message as a
very short one in a persons native language to her mobile phone, and at
the same time full text in English to the system log.


>> template<typename T>
>> inline std:stream&& operator<<( std:stream&& s, const T& t )
>> {
>> std:stream s2( s ); // if future ostreams get move semantics
>> operator<<( s2, t );
>> return std::move( s2 );
>> }
>>
>>
>> 2. Why don't I get an infinite recursion as you suggested in an
>> earlier post? I tried to clarify for the compiler which function I was
>> looking for with following.

>
> In the body of the op<< function above, the rvalue reference parameter s
> behaves as an lvalue. (This was one of the key changes to the current
> implementation, IIUC). Thus, it's presence in the return statement
>
> return operator<<( a, t );
>
> will select an overload that accepts an lvalue as its first argument, if
> one is available (as, I would suggest, there clearly is).
>


Does this mean that my delegator will be valid in C++0x?

>> template<typename T>
>> inline std:stream&& operator<<( std:stream&& s, const T& t )
>> {
>> return std::move( operator<< <S&, const T&>( s, t ) );
>> } ^

> |
> What is `S' here ------------------
>> but got
>>
>> error: no matching function for call to 'operator<<(std:stream&,
>> const B&)'
>>
>> That is strange since that function does exist.

>
> Again, a *complete* compilable example would be necessary here in order
> to permit me to comment on this.


I don't know where that S came from. It should be like this.

template<typename T>
inline std:stream&& operator<<( std:stream&& s, const T& t )
{
return std::move( operator<< <std:stream&, const T&>( s, t ) );
}

Isn't it strange that it can't find that operator<< <std:stream&,
const T&> ?

Is the reason that when I use <std:stream&, const T&> it is looking
for a non-member /template/ function, but my function

std:stream& operator<<( std:stream&, const B& );

is not built out of a template?


>> How do I convert a SomeClass&& to a SomeClass& ? It's not possible
>> unless SomeClass has move semantics, right?

>
> Under what circumstances would you want to do this, given the
> fundamental difference between rvalue references (as, effectively,
> temporary objects) and lvalues (as named regions of addressable
> object storage)?
>


As long as the standard says that an rvalue reference behaves as an
lvalue I don't need to convert. I was just thinking for my delegator,
that when it delegates, the next operator<< should not really care where
the memory comes from; if it is static, stack or a temporary shouldn't
matter.

Part of the question is also for my own understanding of how the
creators of rvalue references see this new feature. I don't want to use
rvalue references in the "wrong" way, and then years after coding
someone says; "do never use rvalue references like that!".


 
Reply With Quote
 
Paul Bibbings
Guest
Posts: n/a
 
      04-29-2010
DeMarcus <(E-Mail Removed)> writes:

> Paul Bibbings wrote:

<snip />
>> Since, at each change, you present only snippets of code, it is very
>> important, in order to maintain context in my own mind, that I can make
>> assumptions about what I have seen already. Effectively, I am forced to
>> ask: "So, which /is/ your delegator?"
>>

>
> The final one is this for sure.
>
> template<typename T>
> inline A&& operator<<( A&& a, const T& t )
> {
> std::cout << "Delegating..." << std::endl;
> return std::move( operator<<( a, t ) );
> }
>
> I will be able to do modifications to the stream-like A.


Okay, that's clear.

<snip />
>>
>> In the body of the op<< function above, the rvalue reference parameter s
>> behaves as an lvalue. (This was one of the key changes to the current
>> implementation, IIUC). Thus, it's presence in the return statement
>>
>> return operator<<( a, t );
>>
>> will select an overload that accepts an lvalue as its first argument, if
>> one is available (as, I would suggest, there clearly is).
>>

>
> Does this mean that my delegator will be valid in C++0x?


Based on what I understand from what you have given, then this will do
the job I feel.

<snip />

> template<typename T>
> inline std:stream&& operator<<( std:stream&& s, const T& t )
> {
> return std::move( operator<< <std:stream&, const T&>( s, t ) );
> }
>
> Isn't it strange that it can't find that operator<< <std:stream&,
> const T&> ?
>
> Is the reason that when I use <std:stream&, const T&> it is looking
> for a non-member /template/ function, but my function
>
> std:stream& operator<<( std:stream&, const B& );
>
> is not built out of a template?


Yes. This is certainly the case. Your op<< overload here is not a
template, but the usage:

operator<< <std:stream&, const T&>( s, t )

is asking the compiler to locate a specific instantiation of a function
*template* that is not present. Having not been able to find it, it
won't find your non-template version in its place since you have
specifically requested a template by providing the template arguments.

>
>>> How do I convert a SomeClass&& to a SomeClass& ? It's not possible
>>> unless SomeClass has move semantics, right?

>>
>> Under what circumstances would you want to do this, given the
>> fundamental difference between rvalue references (as, effectively,
>> temporary objects) and lvalues (as named regions of addressable
>> object storage)?
>>

>
> As long as the standard says that an rvalue reference behaves as an
> lvalue I don't need to convert. I was just thinking for my delegator,
> that when it delegates, the next operator<< should not really care
> where the memory comes from; if it is static, stack or a temporary
> shouldn't matter.
>
> Part of the question is also for my own understanding of how the
> creators of rvalue references see this new feature. I don't want to
> use rvalue references in the "wrong" way, and then years after coding
> someone says; "do never use rvalue references like that!".


To make it just a little more work in getting an accurate
understanding you should be aware that the new Standard expands on the
original pairing of rvalue/lvalue expression categories to:

expression
/ \
/ \
glvalue rvalue
/ \ / \
/ \ / \
lvalue xvalue prvalue

The details of this are in [basic.lval] §3.10. In this context an xvalue
(or eXpiring value) is "an object, usually near the end of its lifetime
(so that its resources may be moved, for example)... [Example: The
result of calling a function whose return type is an rvalue reference is
an xvalue --end example]

Further on, the following is what we have been discussing in relation to
your `delegator':

[expr] §5/6 "[Note: ... In general, the effect of this rule is that
named rvalue references are treated as lvalues and unnamed rvalue
references to objects are treated as xvalues..."

In your delegator, the return value is an unnamed rvalue reference and
as such in an xvalue (essentially, a temporary). On the other hand,
since your parameter A&& a is a *named* rvalue reference in the context
of the method body, then it is "treated as [an] lvalue..."

This is why you are required to use std::move to construct the return
value in some instances, since the purpose of std::move is to convert
(where required) to an rvalue reference. Where the object returned is
"treated as an lvalue" this conversion is required. Where it isn't
required, say in returning an actual (unnamed) rvalue reference, then
std::move is effectively a no-op.

All in all I think you are getting the correct understanding now and
applying it correctly now, in the context of your design. Essentially,
you were not helped at the outset since your compiler was simply not
doing the finally agreed way, but according to an earlier (superceded)
specification.

Regards

Paul Bibbings



 
Reply With Quote
 
DeMarcus
Guest
Posts: n/a
 
      04-29-2010
Paul Bibbings wrote:
> DeMarcus <(E-Mail Removed)> writes:
>
>> Paul Bibbings wrote:

> <snip />
>>> Since, at each change, you present only snippets of code, it is very
>>> important, in order to maintain context in my own mind, that I can make
>>> assumptions about what I have seen already. Effectively, I am forced to
>>> ask: "So, which /is/ your delegator?"
>>>

>> The final one is this for sure.
>>
>> template<typename T>
>> inline A&& operator<<( A&& a, const T& t )
>> {
>> std::cout << "Delegating..." << std::endl;
>> return std::move( operator<<( a, t ) );
>> }
>>
>> I will be able to do modifications to the stream-like A.

>
> Okay, that's clear.
>
> <snip />
>>> In the body of the op<< function above, the rvalue reference parameter s
>>> behaves as an lvalue. (This was one of the key changes to the current
>>> implementation, IIUC). Thus, it's presence in the return statement
>>>
>>> return operator<<( a, t );
>>>
>>> will select an overload that accepts an lvalue as its first argument, if
>>> one is available (as, I would suggest, there clearly is).
>>>

>> Does this mean that my delegator will be valid in C++0x?

>
> Based on what I understand from what you have given, then this will do
> the job I feel.
>
> <snip />
>
>> template<typename T>
>> inline std:stream&& operator<<( std:stream&& s, const T& t )
>> {
>> return std::move( operator<< <std:stream&, const T&>( s, t ) );
>> }
>>
>> Isn't it strange that it can't find that operator<< <std:stream&,
>> const T&> ?
>>
>> Is the reason that when I use <std:stream&, const T&> it is looking
>> for a non-member /template/ function, but my function
>>
>> std:stream& operator<<( std:stream&, const B& );
>>
>> is not built out of a template?

>
> Yes. This is certainly the case. Your op<< overload here is not a
> template, but the usage:
>
> operator<< <std:stream&, const T&>( s, t )
>
> is asking the compiler to locate a specific instantiation of a function
> *template* that is not present. Having not been able to find it, it
> won't find your non-template version in its place since you have
> specifically requested a template by providing the template arguments.
>
>>>> How do I convert a SomeClass&& to a SomeClass& ? It's not possible
>>>> unless SomeClass has move semantics, right?
>>> Under what circumstances would you want to do this, given the
>>> fundamental difference between rvalue references (as, effectively,
>>> temporary objects) and lvalues (as named regions of addressable
>>> object storage)?
>>>

>> As long as the standard says that an rvalue reference behaves as an
>> lvalue I don't need to convert. I was just thinking for my delegator,
>> that when it delegates, the next operator<< should not really care
>> where the memory comes from; if it is static, stack or a temporary
>> shouldn't matter.
>>
>> Part of the question is also for my own understanding of how the
>> creators of rvalue references see this new feature. I don't want to
>> use rvalue references in the "wrong" way, and then years after coding
>> someone says; "do never use rvalue references like that!".

>
> To make it just a little more work in getting an accurate
> understanding you should be aware that the new Standard expands on the
> original pairing of rvalue/lvalue expression categories to:
>
> expression
> / \
> / \
> glvalue rvalue
> / \ / \
> / \ / \
> lvalue xvalue prvalue
>
> The details of this are in [basic.lval] §3.10. In this context an xvalue
> (or eXpiring value) is "an object, usually near the end of its lifetime
> (so that its resources may be moved, for example)... [Example: The
> result of calling a function whose return type is an rvalue reference is
> an xvalue --end example]
>
> Further on, the following is what we have been discussing in relation to
> your `delegator':
>
> [expr] §5/6 "[Note: ... In general, the effect of this rule is that
> named rvalue references are treated as lvalues and unnamed rvalue
> references to objects are treated as xvalues..."
>
> In your delegator, the return value is an unnamed rvalue reference and
> as such in an xvalue (essentially, a temporary). On the other hand,
> since your parameter A&& a is a *named* rvalue reference in the context
> of the method body, then it is "treated as [an] lvalue..."
>
> This is why you are required to use std::move to construct the return
> value in some instances, since the purpose of std::move is to convert
> (where required) to an rvalue reference. Where the object returned is
> "treated as an lvalue" this conversion is required. Where it isn't
> required, say in returning an actual (unnamed) rvalue reference, then
> std::move is effectively a no-op.
>
> All in all I think you are getting the correct understanding now and
> applying it correctly now, in the context of your design. Essentially,
> you were not helped at the outset since your compiler was simply not
> doing the finally agreed way, but according to an earlier (superceded)
> specification.
>
> Regards
>
> Paul Bibbings
>
>
>


Thank you very much Paul!

Your patience and effort is highly appreciated, and I'm very thankful!

Best Regards,
Daniel



 
Reply With Quote
 
DeMarcus
Guest
Posts: n/a
 
      04-30-2010
tonydee wrote:
>> #include "A.hpp"
>> #include "B.hpp"
>>
>> int main()
>> {
>> A a;
>> B b;
>>
>> a << b;
>> A() << b;
>>
>> }

>
> Sorry, I haven't bothered to read through all of this - you're using
> an MS compiler I don't have handy anyway - but if this is a "more
> illustrating" example of anything, then it can only be that a << b and
> A() << b don't produce the same result. Perhaps your issue is that
> operator<< takes an A by (non-const) reference, which won't be
> selected for the temporary...?
>


Yes, that was the case. I've learnt a lot on this thread.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
LCD TV resolution / DVD resolution ? slonkak DVD Video 0 11-13-2006 02:34 PM
How do you change the Modelsim Cursor Resolution (not simulation resolution) Andrew FPGA VHDL 0 09-26-2005 04:05 AM
Scanning resolution, printing resolution, and downsampling hassy_user Digital Photography 11 10-27-2004 07:18 PM
Resolution resolution Simon Digital Photography 4 02-27-2004 01:53 PM
ISO Resolution Chart and Printing Resolution Jack Yeazel Digital Photography 0 08-11-2003 11:19 PM



Advertisments