Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

std::getline( basic_istream<...> &&input, basic_string<...> &str )

66 views
Skip to first unread message

Bonita Montero

unread,
Oct 30, 2020, 3:01:54 AM10/30/20
to
Can anyone tell me why the above prototype has a rvalue ([*]) "input"
but the state if input isn't moved away ? And why I can pass a lvalue
basic_istream<...> here (VC++2019) in C++17-mode ?

[*] https://en.cppreference.com/w/cpp/string/basic_string/getline

Bonita Montero

unread,
Oct 30, 2020, 4:30:49 AM10/30/20
to
Am 30.10.2020 um 08:01 schrieb Bonita Montero:
> [*] https://en.cppreference.com/w/cpp/string/basic_string/getline

I think my code works because the old version isn't deprecated.
But for what is the version with the rvalue-"input" good ?

Bonita Montero

unread,
Oct 30, 2020, 5:01:45 AM10/30/20
to
>> [*] https://en.cppreference.com/w/cpp/string/basic_string/getline

> I think my code works because the old version isn't deprecated.
> But for what is the version with the rvalue-"input" good ?

Maybe it's good for accepting temporaries. But what kind
of temporaries should this be ? One-shot ifstreams ???

Chris Vine

unread,
Oct 30, 2020, 6:11:20 AM10/30/20
to
The overload taking a lvalue reference is (for good reason) not const
so it cannot take a rvalue reference. The overload taking a rvalue
reference is presumably there in order to fill that gap.

Why would anyone want to pass a temporary to std::getline? Dunno, it
seems somewhat improbable. Probably it is there just for the purposes
of symmetry.

Alf P. Steinbach

unread,
Oct 30, 2020, 6:45:36 AM10/30/20
to
You can do things like

getline( istringstream( poem ), first_line );

But I don't know if that's the rationale.

It seems a little weird to me.


- Alf

Öö Tiib

unread,
Oct 30, 2020, 8:59:08 AM10/30/20
to
Read up on "perfect forwarding". Basically, since it is template these
are not rvalue references but universal references.

Chris Vine

unread,
Oct 30, 2020, 9:15:54 AM10/30/20
to
They 'input' argument of std::getline is not taken by universal
reference. If it were, the lvalue reference and rvalue reference
overloads would be unnecessary.

The non-const argument 'std::basic_istream<CharT,Traits>& input' takes
an lvalue only. The argument 'std::basic_istream<CharT,Traits>&& input'
takes a rvalue only. The argument 'std::basic_string<CharT, Traits,
Allocator>& str' is an out parameter which takes a lvalue only.

Given a template type T, an argument 'T&& t' represents a universal (aka
forwarding) reference. That is not the case here.

Chris Vine

unread,
Oct 30, 2020, 9:44:50 AM10/30/20
to
On Fri, 30 Oct 2020 13:15:27 +0000
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> Given a template type T, an argument 'T&& t' represents a universal (aka
> forwarding) reference. That is not the case here.

Perhaps I should add for any learners that this only applies if T is a
deduced type. So (2) below does not represent a forwarding reference:

template <class T> struct S {

template <class U>
void do_it1(U&& u) { ... } // (1) forwarding reference

void do_it2(T&& t) { ... } // (2) rvalue reference

template <class U>
void do_it3(std::list<U>&& l) { ... } // (3) rvalue reference

void do_it4(std::list<T>&& l) { ... } // (4) rvalue reference

};

Öö Tiib

unread,
Oct 30, 2020, 2:02:58 PM10/30/20
to
OK, I apparently mixed it up, mea culpa. Thanks for clarifying.

red floyd

unread,
Oct 30, 2020, 2:44:55 PM10/30/20
to
maybe for this:

std::getline(std:istringstream("some text ...."), ...);

Bonita Montero

unread,
Oct 30, 2020, 3:11:17 PM10/30/20
to
Am 30.10.2020 um 19:44 schrieb red floyd:
> maybe for this:
> std::getline(std:istringstream("some text ...."), ...);

std::getline( std::istringstream( "some text" ), str );
is the same as
str = "some text";
So there's no need for this pattern.

red floyd

unread,
Oct 30, 2020, 5:50:37 PM10/30/20
to
Fine.

std::string some_text; // may have new lines
std::string str;

std::getline(some_text, str);

red floyd

unread,
Oct 30, 2020, 5:51:08 PM10/30/20
to
That's

std::getline(std::istringstream(some_text), str);


Bonita Montero

unread,
Oct 31, 2020, 3:10:25 AM10/31/20
to
> std::getline(std::istringstream(some_text), str);

std::string str( "***" );
... is shorter and faster.


red floyd

unread,
Nov 2, 2020, 1:38:58 AM11/2/20
to
And if some_text is a std:string containing multiple lines of text, that
was read from an external source?

Bonita Montero

unread,
Nov 2, 2020, 1:54:56 AM11/2/20
to
>>> std::getline(std::istringstream(some_text), str);

>> std::string str( "***" );
>> ... is shorter and faster.

> And if some_text is a std:string containing multiple lines of text, that
> was read from an external source?

The given example was a static string.

red floyd

unread,
Nov 2, 2020, 4:21:35 AM11/2/20
to
And then my follow up was a generic std::string.

Bonita Montero

unread,
Nov 2, 2020, 4:58:49 AM11/2/20
to
>> The given example was a static string.

> And then my follow up was a generic std::string.

But that's another issue.
But if you want to have it that way; this should be much faster:

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

int main()
{
string strA( "hello\nworld" );
string strB( strA.substr( 0, find_if( strA.begin(), strA.end(), [](
char c ) { return c == '\n'; } ) - strA.begin() ) );
cout << strB << endl;
}

Paavo Helde

unread,
Nov 2, 2020, 8:43:13 AM11/2/20
to
And this is shorter and not slower:

#include <iostream>
#include <string>

int main() {
std::string strA("hello\nworld");
std::string strB(strA, 0, strA.find('\n'));
std::cout << strB << "\n";
}

red floyd

unread,
Nov 2, 2020, 1:42:49 PM11/2/20
to
I'm not saying this is the best or most efficient way. I'm suggesting
it was a rationale for adding the overload.


Bonita Montero

unread,
Nov 3, 2020, 10:49:24 AM11/3/20
to
>>> #include <iostream>
>>> #include <string>
>>> #include <algorithm>
>>>
>>> using namespace std;
>>>
>>> int main()
>>> {
>>>      string strA( "hello\nworld" );
>>>      string strB( strA.substr( 0, find_if( strA.begin(), strA.end(),
>>> []( char c ) { return c == '\n'; } ) - strA.begin() ) );
>>>      cout << strB << endl;
>>> }

>> And this is shorter and not slower:
>>
>> #include <iostream>
>> #include <string>
>>
>> int main() {
>>      std::string strA("hello\nworld");
>>      std::string strB(strA, 0, strA.find('\n'));
>>      std::cout << strB << "\n";
>> }

> I'm not saying this is the best or most efficient way.
> I'm suggesting it was a rationale for adding the overload.

Consider what we've shown as alternatives that make this
overload superfluous.

0 new messages