Yes, but in this case you are passing a char* which will create a temporary string. You can't bind a temporary object to a reference, so you will have to use const std::string&, std::string or std::string&& as the parameter type in this case.

This means that you have tried to use a `char*` or a `char` array as actual argument for the `std::string&` formal argument.

Since `std::string&` is a reference-to-non-`const`, where the function can /modify/ the actual argument object, you need an actual argument of the exact same type or a class derived from that type (in the latter case the reference is bound to the `std::string` base class sub-object).

The function can't very well modify an instance of some other type as if it were a `std::string`.

Because now the argument is passed by value, which means that the actual argument is copied or converted, or the behavior is /as if/ there is a copying or conversion.

And `std::string` provides a constructor that accepts a `char const*`. I.e. you get an automatic conversion.

The function's code now operates on a copy or an instance resulting from a conversion, and so it can't affect the original argument, in your specific case the `char` array.

> Is it not possible to use std::string by reference?

That's possible.

Since the function /returns/ a `std::string` you probably wanted `std::string const&` anyway. :-)

Cheers & hth.,

- Alf

K. Frank

6/13/2016 1:41:00 PM

0

Hi Ian!

On Sunday, June 12, 2016 at 3:57:15 PM UTC-4, Ian Collins wrote:> On 06/13/16 07:47 AM, James Moe wrote:> > ...> > pmmsend.c:449:63: error: invalid initialization of reference of type> > 'std::string& {aka std::basic_string<char>&}' from expression of type> > 'char*'> > ...> > Yes, but in this case you are passing a char* which will create a > temporary string. You can't bind a temporary object to a reference, so > you will have to use const std::string&, std::string or std::string&& as > the parameter type in this case.

Just to be sure I understand:

The language could have permitted passing a temporary asa non-cost reference, f (std::string &str);, but most ofthe time you would be making a mistake doing this, so thelanguage prohibits it.

In this case -- passing in a temporary -- by using anon-const rvalue reference, f (std::string &&str), youare really just telling the compiler that you do wantto do this, and are not making a mistake.

That is, the code generated when binding a temporaryto a non-cost rvalue reference is the same as whatone would have expected (okay, what I would have expected)if binding to a non-cost lvalue reference has beenallowed.

Is this correct, or am I missing something importantabout this specific use case?

> Ian

Thanks for any clarification.

K. Frank

Öö Tiib

6/13/2016 5:31:00 PM

0

On Monday, 13 June 2016 16:40:56 UTC+3, K. Frank wrote:> Hi Ian!> > On Sunday, June 12, 2016 at 3:57:15 PM UTC-4, Ian Collins wrote:> > On 06/13/16 07:47 AM, James Moe wrote:> > > ...> > > pmmsend.c:449:63: error: invalid initialization of reference of type> > > 'std::string& {aka std::basic_string<char>&}' from expression of type> > > 'char*'> > > ...> > > > Yes, but in this case you are passing a char* which will create a > > temporary string. You can't bind a temporary object to a reference, so > > you will have to use const std::string&, std::string or std::string&& as > > the parameter type in this case.> > Just to be sure I understand:> > The language could have permitted passing a temporary as> a non-cost reference, f (std::string &str);, but most of> the time you would be making a mistake doing this, so the> language prohibits it.

The language could have permitted taking l-value reference tor-value or taking r-value reference to l-value but it would bemisleading most of the time. The differences are complexitythat can give benefit in optimizing or mix everything up andconfuse.

It is somewhat similar taking pointer to non-const to string literal:

char* p = "wrong";

For legacy reasons we get only warning about that from mostof the compilers and if we don't attempt to modify *p thenit works fine.

> > In this case -- passing in a temporary -- by using a> non-const rvalue reference, f (std::string &&str), you> are really just telling the compiler that you do want> to do this, and are not making a mistake.

Yes, with that const we have 4 references:

Reference to l-value of type X is 'X&'.Reference to r-value of type X is 'X&&'.Reference to const of type X is 'X const&'.Thing we seemingly need for nothing is 'X const&&'.

> > That is, the code generated when binding a temporary> to a non-cost rvalue reference is the same as what> one would have expected (okay, what I would have expected)> if binding to a non-cost lvalue reference has been> allowed.

It is hard to know what you would had expected. Reference ismeant to be alias name to some value so compiler is not requiredto generate any code about such alias. If a reference is storedsomewhere (for example class member) then to there it goes most likely as memory address but it is nowhere required. Sameis with pointer, it is not specified what its bits mean.

> > Is this correct, or am I missing something important> about this specific use case?

Programming languages are meant for describing behavior of programs and are not for instructing processors. That is thesole little step we have ever taken above assemblers.

James Moe

6/13/2016 6:57:00 PM

0

On 06/12/2016 12:57 PM, Ian Collins wrote:>> > Is it not possible to use std::string by reference?> Yes, but in this case you are passing a char* which will create a > temporary string. You can't bind a temporary object to a reference, [...]> Ah, I understand. Thank you.

-- James Moejmm-list at sohnen-moe dot com

K. Frank

6/13/2016 8:42:00 PM

0

Hello Öö!

On Monday, June 13, 2016 at 1:30:45 PM UTC-4, Öö Tiib wrote:> On Monday, 13 June 2016 16:40:56 UTC+3, K. Frank wrote:> > Hi Ian!> > > > On Sunday, June 12, 2016 at 3:57:15 PM UTC-4, Ian Collins wrote:> > > On 06/13/16 07:47 AM, James Moe wrote:> > > > ...> > > > pmmsend.c:449:63: error: invalid initialization of reference of type> > > > 'std::string& {aka std::basic_string<char>&}' from expression of type> > > > 'char*'> > > > ...> > Just to be sure I understand:> > > > The language could have permitted passing a temporary as> > a non-cost reference, f (std::string &str);, but most of> > the time you would be making a mistake doing this, so the> > language prohibits it.> ...> > That is, the code generated when binding a temporary> > to a non-cost rvalue reference is the same as what> > one would have expected (okay, what I would have expected)> > if binding to a non-cost lvalue reference has been> > allowed.> > It is hard to know what you would had expected.

Here's a not-too-badly-contrived example to illustratewhat I would have expected:

If "// use case 1 -- won't compile" were permitted, whatI would expect would be:

1) A temporary std::string is constructed on the stack from "Good Morning!" 2) The temporary is bound to the non-const reference argument 3) The lifetime of the temporary is extended to when the function call returns 4) The function modifies its (non-const reference) argument in place (and prints it out) 5) The function returns, the temporary's extended lifetime ends, and the temporary is destroyed

This seems quite reasonable, and seems to me to be whatmost people would expect if this were actually permitted.

It's certainly not necessary to permit this -- thework-around is easy and obvious. (And the work-aroundis almost the same as my hypothetical "expected"behavior. The only difference is that the lifetimeof tmp is to the end of its block scope, rather thanjust to when the function returns.)

> ...> > Is this correct, or am I missing something important> > about this specific use case?> > Programming languages are meant for describing behavior of > programs and are not for instructing processors. That is the> sole little step we have ever taken above assemblers.

Well, yes. And it is true that forbidding the binding oftemporaries to non-const references does prevent a certainclass of errors.

But the design of c++ has generally been to beself-consistently flexible, rather than preventing youfrom shooting yourself in the foot.

It just seems to me that permitting the binding of atemporary to non-cost reference would be very much inthe spirit of c++, and would work just fine if implementedas I described above, unless there is some other setof problems I've overlooked.

I'm not proposing that the language permit this. I'mjust asking whether the language could have easilypermitted this (for example, as outlined above), orwhether I'm missing something and trying to permit thiswould generate a whole other set of complications thatI've overlooked.

Thanks for any further enlightenment.

K. Frank

Paavo Helde

6/13/2016 9:30:00 PM

0

On 13.06.2016 16:40, K. Frank wrote:> Hi Ian!>> On Sunday, June 12, 2016 at 3:57:15 PM UTC-4, Ian Collins wrote:>> On 06/13/16 07:47 AM, James Moe wrote:>>> ...>>> pmmsend.c:449:63: error: invalid initialization of reference of type>>> 'std::string& {aka std::basic_string<char>&}' from expression of type>>> 'char*'>>> ...>>>> Yes, but in this case you are passing a char* which will create a>> temporary string. You can't bind a temporary object to a reference, so>> you will have to use const std::string&, std::string or std::string&& as>> the parameter type in this case.>> Just to be sure I understand:>> The language could have permitted passing a temporary as> a non-cost reference, f (std::string &str);, but most of> the time you would be making a mistake doing this, so the> language prohibits it.

Yes it could, and earlier MSVC versions indeed allowed it for a long time, at least in some situations.

I believe this was prohibited this feature was extremely fragile. Make a innocent-looking change in the code like replacing an int with a long, and the program would silently start misbehaving because a temporary would be created where there was none before, or vice versa.

>> In this case -- passing in a temporary -- by using a> non-const rvalue reference, f (std::string &&str), you> are really just telling the compiler that you do want> to do this, and are not making a mistake.>> That is, the code generated when binding a temporary> to a non-cost rvalue reference is the same as what> one would have expected (okay, what I would have expected)> if binding to a non-cost lvalue reference has been> allowed.

In some sense, this is correct, a temporary would be created and its address passed to the function. What is different are the assumptions what the called function would make: a temporary cannot be used for transporting information out of the function, whereas non-const lvalue references are often used exactly for that purpose.

So from the point of the overall functionality the two scenarios (calling with a non-const lvalue reference and calling with a temporary) differ drastically; using the same syntax for two drastically different things would not be a good design.