Why extracting string from stringstream(a) fails?

Discussion in 'C++' started by Mc Lauren Series, Oct 24, 2009.

  1. #include <iostream>
    #include <sstream>

    using namespace std;

    int main()
    {
    string a("test");
    string b;
    stringstream(a) >> b;
    }

    When I try to execute this code, I get errors:

    foo.c: In function 'int main()':
    foo.c:10: error: no match for 'operator>>' in
    'std::basic_stringstream<char, std::char_traits<char>,
    std::allocator<char> >(((const std::basic_string<char,
    std::char_traits<char>, std::allocator<char> >&)((const
    std::basic_string<char, std::char_traits<char>, std::allocator<char>
    >*)(& a))), std::eek:perator|(_S_out, _S_in)) >> b'


    Why does this error occur? Isn't stringstream(a) supposed to behave
    just like a stream? With cout I can extract string into a string
    variable. Then why not here?
     
    Mc Lauren Series, Oct 24, 2009
    #1
    1. Advertising

  2. Mc Lauren Series wrote:
    > #include <iostream>
    > #include <sstream>
    >
    > using namespace std;
    >
    > int main()
    > {
    > string a("test");
    > string b;
    > stringstream(a) >> b;
    > }
    >
    > When I try to execute this code, I get errors:
    >
    > foo.c: In function 'int main()':
    > foo.c:10: error: no match for 'operator>>' in
    > 'std::basic_stringstream<char, std::char_traits<char>,
    > std::allocator<char> >(((const std::basic_string<char,
    > std::char_traits<char>, std::allocator<char> >&)((const
    > std::basic_string<char, std::char_traits<char>, std::allocator<char>
    >> *)(& a))), std::eek:perator|(_S_out, _S_in)) >> b'

    >
    > Why does this error occur? Isn't stringstream(a) supposed to behave
    > just like a stream? With cout I can extract string into a string
    > variable. Then why not here?


    The operator >> is a non-member. It takes the first argument by a
    non-const reference, which cannot be initialized with a temporary.
    Define a named variable and you will be able to do what you want:

    stringstream sa(a);
    sa >> b;

    There is a trick to overcome this particular limitation, but it's not
    the best approach. You can do something like that

    stringstream(a) >> boolalpha >> b;

    which invokes a non-const member function (which is OK for temporaries)
    and the function (that "outputs" a manipulator) returns a non-const
    reference, which then can be passed to the non-member operator<<.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Oct 24, 2009
    #2
    1. Advertising

  3. On Oct 25, 3:28 am, Victor Bazarov <> wrote:
    > Mc Lauren Series wrote:
    > > #include <iostream>
    > > #include <sstream>

    >
    > > using namespace std;

    >
    > > int main()
    > > {
    > >     string a("test");
    > >     string b;
    > >     stringstream(a) >> b;
    > > }

    >
    > > When I try to execute this code, I get errors:

    >
    > > foo.c: In function 'int main()':
    > > foo.c:10: error: no match for 'operator>>' in
    > > 'std::basic_stringstream<char, std::char_traits<char>,
    > > std::allocator<char> >(((const std::basic_string<char,
    > > std::char_traits<char>, std::allocator<char> >&)((const
    > > std::basic_string<char, std::char_traits<char>, std::allocator<char>
    > >> *)(& a))), std::eek:perator|(_S_out, _S_in)) >> b'

    >
    > > Why does this error occur? Isn't stringstream(a) supposed to behave
    > > just like a stream? With cout I can extract string into a string
    > > variable. Then why not here?

    >
    > The operator >> is a non-member.  It takes the first argument by a
    > non-const reference, which cannot be initialized with a temporary.
    > Define a named variable and you will be able to do what you want:
    >
    >      stringstream sa(a);
    >      sa >> b;
    >
    > There is a trick to overcome this particular limitation, but it's not
    > the best approach.  You can do something like that
    >
    >      stringstream(a) >> boolalpha >> b;
    >
    > which invokes a non-const member function (which is OK for temporaries)
    > and the function (that "outputs" a manipulator) returns a non-const
    > reference, which then can be passed to the non-member operator<<.
    >
    > V
    > --
    > Please remove capital 'A's when replying by e-mail
    > I do not respond to top-posted replies, please don't ask


    If >> is a non-member, why does this work?

    #include <iostream>
    #include <sstream>
    #include <string>

    using namespace std;

    int main()
    {
    string a("1234");
    // string b;
    int b;
    stringstream(a) >> b;
    cout << b << endl;
    }


    If we change the data type of b to int, the code works fine but not
    with b as string. Why?
     
    Mc Lauren Series, Oct 25, 2009
    #3
  4. On 25/10/09 06:17, Mc Lauren Series wrote:
    > On Oct 25, 3:28 am, Victor Bazarov<> wrote:
    >> Mc Lauren Series wrote:
    >>> #include<iostream>
    >>> #include<sstream>

    >>
    >>> using namespace std;

    >>
    >>> int main()
    >>> {
    >>> string a("test");
    >>> string b;
    >>> stringstream(a)>> b;
    >>> }

    >>
    >>> When I try to execute this code, I get errors:

    >>
    >>> foo.c: In function 'int main()':
    >>> foo.c:10: error: no match for 'operator>>' in
    >>> 'std::basic_stringstream<char, std::char_traits<char>,
    >>> std::allocator<char> >(((const std::basic_string<char,
    >>> std::char_traits<char>, std::allocator<char> >&)((const
    >>> std::basic_string<char, std::char_traits<char>, std::allocator<char>
    >>>> *)(& a))), std::eek:perator|(_S_out, _S_in))>> b'

    >>
    >>> Why does this error occur? Isn't stringstream(a) supposed to behave
    >>> just like a stream? With cout I can extract string into a string
    >>> variable. Then why not here?

    >>
    >> The operator>> is a non-member. It takes the first argument by a
    >> non-const reference, which cannot be initialized with a temporary.
    >> Define a named variable and you will be able to do what you want:
    >>
    >> stringstream sa(a);
    >> sa>> b;
    >>
    >> There is a trick to overcome this particular limitation, but it's not
    >> the best approach. You can do something like that
    >>
    >> stringstream(a)>> boolalpha>> b;
    >>
    >> which invokes a non-const member function (which is OK for temporaries)
    >> and the function (that "outputs" a manipulator) returns a non-const
    >> reference, which then can be passed to the non-member operator<<.


    >
    > If>> is a non-member, why does this work?
    >


    Some stream operators are member functions, others are not. Member
    functions can be called on temporary objects. boolalpha is handled by a
    member function which returns std::istream&. That std::istream& can than
    be accepted by both member and non-member operator>> functions.

    > #include<iostream>
    > #include<sstream>
    > #include<string>
    >
    > using namespace std;
    >
    > int main()
    > {
    > string a("1234");
    > // string b;
    > int b;
    > stringstream(a)>> b;
    > cout<< b<< endl;
    > }
    >
    >
    > If we change the data type of b to int, the code works fine but not
    > with b as string. Why?


    Because extracting into an integer is handled by a member function of
    std::istream base class of std::stringstream.

    Here is another trick to turn a temporary into an l-value, so that any
    operator>> can work on a temporary stream object:

    template<class T>
    inline T& lvalue(T const& t) {
    return const_cast<T&>(t);
    }

    This function template is supposed to be used like this:

    lvalue(stringstream(a)) >> ...;

    Alternatively, boost::lexical_cast<> converts between types using
    streams and its usage is simpler:

    int b = boost::lexical_cast<int>("1234");

    Using streams directly as you do allows to extract more than one value
    at once though.

    --
    Max
     
    Maxim Yegorushkin, Oct 25, 2009
    #4
  5. Maxim Yegorushkin wrote:

    > On 25/10/09 06:17, Mc Lauren Series wrote:
    >> On Oct 25, 3:28 am, Victor Bazarov<> wrote:
    >>> Mc Lauren Series wrote:
    >>>> #include<iostream>
    >>>> #include<sstream>
    >>>
    >>>> using namespace std;
    >>>
    >>>> int main()
    >>>> {
    >>>> string a("test");
    >>>> string b;
    >>>> stringstream(a)>> b;
    >>>> }
    >>>
    >>>> When I try to execute this code, I get errors:
    >>>
    >>>> foo.c: In function 'int main()':
    >>>> foo.c:10: error: no match for 'operator>>' in
    >>>> 'std::basic_stringstream<char, std::char_traits<char>,
    >>>> std::allocator<char> >(((const std::basic_string<char,
    >>>> std::char_traits<char>, std::allocator<char> >&)((const
    >>>> std::basic_string<char, std::char_traits<char>, std::allocator<char>
    >>>>> *)(& a))), std::eek:perator|(_S_out, _S_in))>> b'
    >>>
    >>>> Why does this error occur? Isn't stringstream(a) supposed to behave
    >>>> just like a stream? With cout I can extract string into a string
    >>>> variable. Then why not here?
    >>>
    >>> The operator>> is a non-member. It takes the first argument by a
    >>> non-const reference, which cannot be initialized with a temporary.
    >>> Define a named variable and you will be able to do what you want:
    >>>
    >>> stringstream sa(a);
    >>> sa>> b;
    >>>
    >>> There is a trick to overcome this particular limitation, but it's not
    >>> the best approach. You can do something like that
    >>>
    >>> stringstream(a)>> boolalpha>> b;
    >>>
    >>> which invokes a non-const member function (which is OK for temporaries)
    >>> and the function (that "outputs" a manipulator) returns a non-const
    >>> reference, which then can be passed to the non-member operator<<.

    >
    >>
    >> If>> is a non-member, why does this work?
    >>

    >
    > Some stream operators are member functions, others are not. Member
    > functions can be called on temporary objects. boolalpha is handled by a
    > member function which returns std::istream&. That std::istream& can than
    > be accepted by both member and non-member operator>> functions.
    >
    >> #include<iostream>
    >> #include<sstream>
    >> #include<string>
    >>
    >> using namespace std;
    >>
    >> int main()
    >> {
    >> string a("1234");
    >> // string b;
    >> int b;
    >> stringstream(a)>> b;
    >> cout<< b<< endl;
    >> }
    >>
    >>
    >> If we change the data type of b to int, the code works fine but not
    >> with b as string. Why?

    >
    > Because extracting into an integer is handled by a member function of
    > std::istream base class of std::stringstream.
    >
    > Here is another trick to turn a temporary into an l-value, so that any
    > operator>> can work on a temporary stream object:
    >
    > template<class T>
    > inline T& lvalue(T const& t) {
    > return const_cast<T&>(t);
    > }
    >

    Although this will be ill-formed because it requires the stream to have a
    copy constructor. You could also use this trickery which i believe is safe:

    template<typename T>
    struct Lv {
    T t, &tr;
    Lv():t(), tr(t) {}
    };

    template<typename T>
    T &lvalue(T &t = Lv<T>().tr) { return t; }

    "lvalue<stringstream>()" now gives an lvalue of type stringstream, but this
    doesn't allow passing arguments to its constructor :(
     
    Johannes Schaub (litb), Oct 25, 2009
    #5
  6. Johannes Schaub (litb) wrote:

    > Maxim Yegorushkin wrote:
    >
    >> On 25/10/09 06:17, Mc Lauren Series wrote:
    >>> On Oct 25, 3:28 am, Victor Bazarov<> wrote:
    >>>> Mc Lauren Series wrote:
    >>>>> #include<iostream>
    >>>>> #include<sstream>
    >>>>
    >>>>> using namespace std;
    >>>>
    >>>>> int main()
    >>>>> {
    >>>>> string a("test");
    >>>>> string b;
    >>>>> stringstream(a)>> b;
    >>>>> }
    >>>>
    >>>>> When I try to execute this code, I get errors:
    >>>>
    >>>>> foo.c: In function 'int main()':
    >>>>> foo.c:10: error: no match for 'operator>>' in
    >>>>> 'std::basic_stringstream<char, std::char_traits<char>,
    >>>>> std::allocator<char> >(((const std::basic_string<char,
    >>>>> std::char_traits<char>, std::allocator<char> >&)((const
    >>>>> std::basic_string<char, std::char_traits<char>, std::allocator<char>
    >>>>>> *)(& a))), std::eek:perator|(_S_out, _S_in))>> b'
    >>>>
    >>>>> Why does this error occur? Isn't stringstream(a) supposed to behave
    >>>>> just like a stream? With cout I can extract string into a string
    >>>>> variable. Then why not here?
    >>>>
    >>>> The operator>> is a non-member. It takes the first argument by a
    >>>> non-const reference, which cannot be initialized with a temporary.
    >>>> Define a named variable and you will be able to do what you want:
    >>>>
    >>>> stringstream sa(a);
    >>>> sa>> b;
    >>>>
    >>>> There is a trick to overcome this particular limitation, but it's not
    >>>> the best approach. You can do something like that
    >>>>
    >>>> stringstream(a)>> boolalpha>> b;
    >>>>
    >>>> which invokes a non-const member function (which is OK for temporaries)
    >>>> and the function (that "outputs" a manipulator) returns a non-const
    >>>> reference, which then can be passed to the non-member operator<<.

    >>
    >>>
    >>> If>> is a non-member, why does this work?
    >>>

    >>
    >> Some stream operators are member functions, others are not. Member
    >> functions can be called on temporary objects. boolalpha is handled by a
    >> member function which returns std::istream&. That std::istream& can than
    >> be accepted by both member and non-member operator>> functions.
    >>
    >>> #include<iostream>
    >>> #include<sstream>
    >>> #include<string>
    >>>
    >>> using namespace std;
    >>>
    >>> int main()
    >>> {
    >>> string a("1234");
    >>> // string b;
    >>> int b;
    >>> stringstream(a)>> b;
    >>> cout<< b<< endl;
    >>> }
    >>>
    >>>
    >>> If we change the data type of b to int, the code works fine but not
    >>> with b as string. Why?

    >>
    >> Because extracting into an integer is handled by a member function of
    >> std::istream base class of std::stringstream.
    >>
    >> Here is another trick to turn a temporary into an l-value, so that any
    >> operator>> can work on a temporary stream object:
    >>
    >> template<class T>
    >> inline T& lvalue(T const& t) {
    >> return const_cast<T&>(t);
    >> }
    >>

    > Although this will be ill-formed because it requires the stream to have a
    > copy constructor. You could also use this trickery which i believe is
    > safe:
    >
    > template<typename T>
    > struct Lv {
    > T t, &tr;
    > Lv():t(), tr(t) {}
    > };
    >
    > template<typename T>
    > T &lvalue(T &t = Lv<T>().tr) { return t; }
    >
    > "lvalue<stringstream>()" now gives an lvalue of type stringstream, but
    > this doesn't allow passing arguments to its constructor :(
    >

    If you want, though, you can change it to

    template<typename T>
    struct Lv {
    T t, &tr;
    Lv():t(), tr(t) {}
    template<typename U1>
    Lv(U1 const& u1):t(u1), tr(t) { }
    };

    And you can do Lv<stringstream>("hello").tr to get the lvalue, which isn't
    too bad i think, it just doesn't look nice. Packaged into a macro

    #define LVALUE(TY, EX) Lv<Ty> EX . tr

    It can look much better like LVALUE(stringstream,("hello")) :)
     
    Johannes Schaub (litb), Oct 25, 2009
    #6
  7. On 25/10/09 18:13, Johannes Schaub (litb) wrote:
    > Maxim Yegorushkin wrote:
    >
    >> On 25/10/09 06:17, Mc Lauren Series wrote:
    >>> On Oct 25, 3:28 am, Victor Bazarov<> wrote:
    >>>> Mc Lauren Series wrote:
    >>>>> #include<iostream>
    >>>>> #include<sstream>
    >>>>
    >>>>> using namespace std;
    >>>>
    >>>>> int main()
    >>>>> {
    >>>>> string a("test");
    >>>>> string b;
    >>>>> stringstream(a)>> b;
    >>>>> }
    >>>>
    >>>>> When I try to execute this code, I get errors:
    >>>>
    >>>>> foo.c: In function 'int main()':
    >>>>> foo.c:10: error: no match for 'operator>>' in
    >>>>> 'std::basic_stringstream<char, std::char_traits<char>,
    >>>>> std::allocator<char> >(((const std::basic_string<char,
    >>>>> std::char_traits<char>, std::allocator<char> >&)((const
    >>>>> std::basic_string<char, std::char_traits<char>, std::allocator<char>
    >>>>>> *)(& a))), std::eek:perator|(_S_out, _S_in))>> b'
    >>>>
    >>>>> Why does this error occur? Isn't stringstream(a) supposed to behave
    >>>>> just like a stream? With cout I can extract string into a string
    >>>>> variable. Then why not here?
    >>>>
    >>>> The operator>> is a non-member. It takes the first argument by a
    >>>> non-const reference, which cannot be initialized with a temporary.
    >>>> Define a named variable and you will be able to do what you want:
    >>>>
    >>>> stringstream sa(a);
    >>>> sa>> b;
    >>>>
    >>>> There is a trick to overcome this particular limitation, but it's not
    >>>> the best approach. You can do something like that
    >>>>
    >>>> stringstream(a)>> boolalpha>> b;
    >>>>
    >>>> which invokes a non-const member function (which is OK for temporaries)
    >>>> and the function (that "outputs" a manipulator) returns a non-const
    >>>> reference, which then can be passed to the non-member operator<<.

    >>
    >>>
    >>> If>> is a non-member, why does this work?
    >>>

    >>
    >> Some stream operators are member functions, others are not. Member
    >> functions can be called on temporary objects. boolalpha is handled by a
    >> member function which returns std::istream&. That std::istream& can than
    >> be accepted by both member and non-member operator>> functions.
    >>
    >>> #include<iostream>
    >>> #include<sstream>
    >>> #include<string>
    >>>
    >>> using namespace std;
    >>>
    >>> int main()
    >>> {
    >>> string a("1234");
    >>> // string b;
    >>> int b;
    >>> stringstream(a)>> b;
    >>> cout<< b<< endl;
    >>> }
    >>>
    >>>
    >>> If we change the data type of b to int, the code works fine but not
    >>> with b as string. Why?

    >>
    >> Because extracting into an integer is handled by a member function of
    >> std::istream base class of std::stringstream.
    >>
    >> Here is another trick to turn a temporary into an l-value, so that any
    >> operator>> can work on a temporary stream object:
    >>
    >> template<class T>
    >> inline T& lvalue(T const& t) {
    >> return const_cast<T&>(t);
    >> }
    >>

    > Although this will be ill-formed because it requires the stream to have a
    > copy constructor.


    Interesting.

    My understanding is that a copy constructor is only required when copy
    initialization is involved or when a conversion is made to initialize a
    function argument. In this case there is no copy initialization or
    conversion happening. Therefore, the code must be well formed.

    Could you elaborate you point please?

    --
    Max
     
    Maxim Yegorushkin, Oct 25, 2009
    #7
  8. * Maxim Yegorushkin:
    > On 25/10/09 18:13, Johannes Schaub (litb) wrote:
    >> Maxim Yegorushkin wrote:
    >>
    >>>
    >>> Here is another trick to turn a temporary into an l-value, so that any
    >>> operator>> can work on a temporary stream object:
    >>>
    >>> template<class T>
    >>> inline T& lvalue(T const& t) {
    >>> return const_cast<T&>(t);
    >>> }
    >>>

    >> Although this will be ill-formed because it requires the stream to have a
    >> copy constructor.

    >
    > Interesting.
    >
    > My understanding is that a copy constructor is only required when copy
    > initialization is involved or when a conversion is made to initialize a
    > function argument. In this case there is no copy initialization or
    > conversion happening. Therefore, the code must be well formed.
    >
    > Could you elaborate you point please?


    It's different in C++98 and C++0x (C++03 is just C++98 with corrections).

    The argument passing is defined as copy initialization. And in C++98 the
    implementation is allowed to make any number of copies of an rvalue actual
    argument passed to 'T const&' formal argument, or for any copy initialization.
    Which means that the type must provide a suitable copy constructor. For example,
    that means that you can't do this thing with a std::auto_ptr. Or a stream.

    In C++0x the implementation can't make such copies when it has an rvalue of
    correct type, it must just pass (initialize the reference with) a direct
    reference to the rvalue object. So this impacts on std::auto_ptr semantics,
    which are different in C++0x. But with C++0x you don't have to and really
    shouldn't use std::auto_ptr anyway, and even in C++98 passing std::auto_ptr by
    reference to const is bad, and the "direct" passing provides a measure of
    sanity. :)


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Oct 25, 2009
    #8
  9. * Alf P. Steinbach:
    > * Maxim Yegorushkin:
    >> On 25/10/09 18:13, Johannes Schaub (litb) wrote:
    >>> Maxim Yegorushkin wrote:
    >>>
    >>>>
    >>>> Here is another trick to turn a temporary into an l-value, so that any
    >>>> operator>> can work on a temporary stream object:
    >>>>
    >>>> template<class T>
    >>>> inline T& lvalue(T const& t) {
    >>>> return const_cast<T&>(t);
    >>>> }
    >>>>
    >>> Although this will be ill-formed because it requires the stream to
    >>> have a
    >>> copy constructor.

    >>
    >> Interesting.
    >>
    >> My understanding is that a copy constructor is only required when copy
    >> initialization is involved or when a conversion is made to initialize
    >> a function argument. In this case there is no copy initialization or
    >> conversion happening. Therefore, the code must be well formed.
    >>
    >> Could you elaborate you point please?

    >
    > It's different in C++98 and C++0x (C++03 is just C++98 with corrections).
    >
    > The argument passing is defined as copy initialization. And in C++98 the
    > implementation is allowed to make any number of copies of an rvalue
    > actual argument passed to 'T const&' formal argument, or for any copy
    > initialization. Which means that the type must provide a suitable copy
    > constructor. For example, that means that you can't do this thing with a
    > std::auto_ptr. Or a stream.
    >
    > In C++0x the implementation can't make such copies when it has an rvalue
    > of correct type, it must just pass (initialize the reference with) a
    > direct reference to the rvalue object. So this impacts on std::auto_ptr
    > semantics, which are different in C++0x. But with C++0x you don't have
    > to and really shouldn't use std::auto_ptr anyway, and even in C++98
    > passing std::auto_ptr by reference to const is bad, and the "direct"
    > passing provides a measure of sanity. :)


    Uhm, remove one "even", sorry.

    Cheers,

    - Alf
     
    Alf P. Steinbach, Oct 25, 2009
    #9
  10. Alf P. Steinbach wrote:
    > * Maxim Yegorushkin:
    >> On 25/10/09 18:13, Johannes Schaub (litb) wrote:
    >>> Maxim Yegorushkin wrote:
    >>>
    >>>>
    >>>> Here is another trick to turn a temporary into an l-value, so that any
    >>>> operator>> can work on a temporary stream object:
    >>>>
    >>>> template<class T>
    >>>> inline T& lvalue(T const& t) {
    >>>> return const_cast<T&>(t);
    >>>> }
    >>>>
    >>> Although this will be ill-formed because it requires the stream to
    >>> have a
    >>> copy constructor.

    >>
    >> Interesting.
    >>
    >> My understanding is that a copy constructor is only required when copy
    >> initialization is involved or when a conversion is made to initialize
    >> a function argument. In this case there is no copy initialization or
    >> conversion happening. Therefore, the code must be well formed.
    >>
    >> Could you elaborate you point please?

    >
    > It's different in C++98 and C++0x (C++03 is just C++98 with corrections).
    >
    > The argument passing is defined as copy initialization. And in C++98 the
    > implementation is allowed to make any number of copies of an rvalue
    > actual argument passed to 'T const&' formal argument, or for any copy
    > initialization. Which means that the type must provide a suitable copy
    > constructor. For example, that means that you can't do this thing with a
    > std::auto_ptr. Or a stream.


    Even more interesting.

    Given the following declaration:

    void foo(int& ref);

    Could you explain how ref argument can possibly be copy-initialized please?

    --
    Max
     
    Maxim Yegorushkin, Oct 26, 2009
    #10
  11. Maxim Yegorushkin wrote:
    > Alf P. Steinbach wrote:
    >> * Maxim Yegorushkin:
    >>> On 25/10/09 18:13, Johannes Schaub (litb) wrote:
    >>>> Maxim Yegorushkin wrote:
    >>>>
    >>>>>
    >>>>> Here is another trick to turn a temporary into an l-value, so that any
    >>>>> operator>> can work on a temporary stream object:
    >>>>>
    >>>>> template<class T>
    >>>>> inline T& lvalue(T const& t) {
    >>>>> return const_cast<T&>(t);
    >>>>> }
    >>>>>
    >>>> Although this will be ill-formed because it requires the stream to
    >>>> have a
    >>>> copy constructor.
    >>>
    >>> Interesting.
    >>>
    >>> My understanding is that a copy constructor is only required when
    >>> copy initialization is involved or when a conversion is made to
    >>> initialize a function argument. In this case there is no copy
    >>> initialization or conversion happening. Therefore, the code must be
    >>> well formed.
    >>>
    >>> Could you elaborate you point please?

    >>
    >> It's different in C++98 and C++0x (C++03 is just C++98 with corrections).
    >>
    >> The argument passing is defined as copy initialization. And in C++98
    >> the implementation is allowed to make any number of copies of an
    >> rvalue actual argument passed to 'T const&' formal argument, or for
    >> any copy initialization. Which means that the type must provide a
    >> suitable copy constructor. For example, that means that you can't do
    >> this thing with a std::auto_ptr. Or a stream.

    >
    > Even more interesting.
    >
    > Given the following declaration:
    >
    > void foo(int& ref);
    >
    > Could you explain how ref argument can possibly be copy-initialized please?
    >


    I am guessing the same way 'r2' is a "copy" of 'r1' here:

    int a = 42;
    int &r1 = a;
    int &r2 = r1;

    :)

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Oct 26, 2009
    #11
  12. Victor Bazarov wrote:
    > Maxim Yegorushkin wrote:
    >> Alf P. Steinbach wrote:
    >>> * Maxim Yegorushkin:
    >>>> On 25/10/09 18:13, Johannes Schaub (litb) wrote:
    >>>>> Maxim Yegorushkin wrote:
    >>>>>
    >>>>>>
    >>>>>> Here is another trick to turn a temporary into an l-value, so that
    >>>>>> any
    >>>>>> operator>> can work on a temporary stream object:
    >>>>>>
    >>>>>> template<class T>
    >>>>>> inline T& lvalue(T const& t) {
    >>>>>> return const_cast<T&>(t);
    >>>>>> }
    >>>>>>
    >>>>> Although this will be ill-formed because it requires the stream to
    >>>>> have a
    >>>>> copy constructor.
    >>>>
    >>>> Interesting.
    >>>>
    >>>> My understanding is that a copy constructor is only required when
    >>>> copy initialization is involved or when a conversion is made to
    >>>> initialize a function argument. In this case there is no copy
    >>>> initialization or conversion happening. Therefore, the code must be
    >>>> well formed.
    >>>>
    >>>> Could you elaborate you point please?
    >>>
    >>> It's different in C++98 and C++0x (C++03 is just C++98 with
    >>> corrections).
    >>>
    >>> The argument passing is defined as copy initialization. And in C++98
    >>> the implementation is allowed to make any number of copies of an
    >>> rvalue actual argument passed to 'T const&' formal argument, or for
    >>> any copy initialization. Which means that the type must provide a
    >>> suitable copy constructor. For example, that means that you can't do
    >>> this thing with a std::auto_ptr. Or a stream.

    >>
    >> Even more interesting.
    >>
    >> Given the following declaration:
    >>
    >> void foo(int& ref);
    >>
    >> Could you explain how ref argument can possibly be copy-initialized
    >> please?
    >>

    >
    > I am guessing the same way 'r2' is a "copy" of 'r1' here:
    >
    > int a = 42;
    > int &r1 = a;
    > int &r2 = r1;
    >
    > :)


    Very well, this is what I wanted to hear. ;)

    In this case no copy constructor is required to copy-initialize a reference to
    non-const. By induction, the same should hold true for references to const
    (although they can be initialized with r-values, but only if necessary). Hence,
    the above lvalue function template is well-formed.

    Comeau online compiles lvalue(std::istringstream(...)) just fine.

    --
    Max
     
    Maxim Yegorushkin, Oct 26, 2009
    #12
  13. Maxim Yegorushkin wrote:

    > Victor Bazarov wrote:
    >> Maxim Yegorushkin wrote:
    >>> Alf P. Steinbach wrote:
    >>>> * Maxim Yegorushkin:
    >>>>> On 25/10/09 18:13, Johannes Schaub (litb) wrote:
    >>>>>> Maxim Yegorushkin wrote:
    >>>>>>
    >>>>>>>
    >>>>>>> Here is another trick to turn a temporary into an l-value, so that
    >>>>>>> any
    >>>>>>> operator>> can work on a temporary stream object:
    >>>>>>>
    >>>>>>> template<class T>
    >>>>>>> inline T& lvalue(T const& t) {
    >>>>>>> return const_cast<T&>(t);
    >>>>>>> }
    >>>>>>>
    >>>>>> Although this will be ill-formed because it requires the stream to
    >>>>>> have a
    >>>>>> copy constructor.
    >>>>>
    >>>>> Interesting.
    >>>>>
    >>>>> My understanding is that a copy constructor is only required when
    >>>>> copy initialization is involved or when a conversion is made to
    >>>>> initialize a function argument. In this case there is no copy
    >>>>> initialization or conversion happening. Therefore, the code must be
    >>>>> well formed.
    >>>>>
    >>>>> Could you elaborate you point please?
    >>>>
    >>>> It's different in C++98 and C++0x (C++03 is just C++98 with
    >>>> corrections).
    >>>>
    >>>> The argument passing is defined as copy initialization. And in C++98
    >>>> the implementation is allowed to make any number of copies of an
    >>>> rvalue actual argument passed to 'T const&' formal argument, or for
    >>>> any copy initialization. Which means that the type must provide a
    >>>> suitable copy constructor. For example, that means that you can't do
    >>>> this thing with a std::auto_ptr. Or a stream.
    >>>
    >>> Even more interesting.
    >>>
    >>> Given the following declaration:
    >>>
    >>> void foo(int& ref);
    >>>
    >>> Could you explain how ref argument can possibly be copy-initialized
    >>> please?
    >>>

    >>
    >> I am guessing the same way 'r2' is a "copy" of 'r1' here:
    >>
    >> int a = 42;
    >> int &r1 = a;
    >> int &r2 = r1;
    >>
    >> :)

    >
    > Very well, this is what I wanted to hear. ;)
    >
    > In this case no copy constructor is required to copy-initialize a
    > reference to non-const. By induction, the same should hold true for
    > references to const
    > (although they can be initialized with r-values, but only if necessary).
    > Hence, the above lvalue function template is well-formed.
    >
    > Comeau online compiles lvalue(std::istringstream(...)) just fine.
    >

    Yes, but if you turn off the C++0x mode, it will error out.
     
    Johannes Schaub (litb), Oct 26, 2009
    #13
  14. Mc Lauren Series

    James Kanze Guest

    On Oct 26, 4:07 pm, Maxim Yegorushkin <>
    wrote:
    > Alf P. Steinbach wrote:
    > > * Maxim Yegorushkin:
    > >> On 25/10/09 18:13, Johannes Schaub (litb) wrote:
    > >>> Maxim Yegorushkin wrote:


    > >>>> Here is another trick to turn a temporary into an
    > >>>> l-value, so that any operator>> can work on a temporary
    > >>>> stream object:


    > >>>> template<class T>
    > >>>> inline T& lvalue(T const& t) {
    > >>>> return const_cast<T&>(t);
    > >>>> }


    > >>> Although this will be ill-formed because it requires the
    > >>> stream to have a copy constructor.


    > >> Interesting.


    > >> My understanding is that a copy constructor is only
    > >> required when copy initialization is involved or when a
    > >> conversion is made to initialize a function argument. In
    > >> this case there is no copy initialization or conversion
    > >> happening. Therefore, the code must be well formed.


    > >> Could you elaborate you point please?


    > > It's different in C++98 and C++0x (C++03 is just C++98 with
    > > corrections).


    > > The argument passing is defined as copy initialization. And
    > > in C++98 the implementation is allowed to make any number of
    > > copies of an rvalue actual argument passed to 'T const&'
    > > formal argument, or for any copy initialization. Which means
    > > that the type must provide a suitable copy constructor. For
    > > example, that means that you can't do this thing with a
    > > std::auto_ptr. Or a stream.


    > Even more interesting.


    > Given the following declaration:


    > void foo(int& ref);


    > Could you explain how ref argument can possibly be
    > copy-initialized please?


    There's more to it that Alf revealed. (It wouldn't be the C++
    standard if it were that simple.) It's copy initialization, so
    the rules for copy initialization apply. The rule that requires
    a copy constructor when copy initialization is used only applies
    when initializing a reference with an rvalue (and this is the
    only time copies are allowed). If the initializer is an lvalue,
    everything is fine---otherwise, things like:
    int i;
    int& ri = i;
    would have somewhat unexpected semantics.

    --
    James Kanze
     
    James Kanze, Oct 26, 2009
    #14
  15. On 26/10/09 17:47, James Kanze wrote:
    > On Oct 26, 4:07 pm, Maxim Yegorushkin<>
    > wrote:
    >> Alf P. Steinbach wrote:
    >>> * Maxim Yegorushkin:
    >>>> On 25/10/09 18:13, Johannes Schaub (litb) wrote:
    >>>>> Maxim Yegorushkin wrote:

    >
    >>>>>> Here is another trick to turn a temporary into an
    >>>>>> l-value, so that any operator>> can work on a temporary
    >>>>>> stream object:

    >
    >>>>>> template<class T>
    >>>>>> inline T& lvalue(T const& t) {
    >>>>>> return const_cast<T&>(t);
    >>>>>> }

    >
    >>>>> Although this will be ill-formed because it requires the
    >>>>> stream to have a copy constructor.

    >
    >>>> Interesting.

    >
    >>>> My understanding is that a copy constructor is only
    >>>> required when copy initialization is involved or when a
    >>>> conversion is made to initialize a function argument. In
    >>>> this case there is no copy initialization or conversion
    >>>> happening. Therefore, the code must be well formed.

    >
    >>>> Could you elaborate you point please?

    >
    >>> It's different in C++98 and C++0x (C++03 is just C++98 with
    >>> corrections).

    >
    >>> The argument passing is defined as copy initialization. And
    >>> in C++98 the implementation is allowed to make any number of
    >>> copies of an rvalue actual argument passed to 'T const&'
    >>> formal argument, or for any copy initialization. Which means
    >>> that the type must provide a suitable copy constructor. For
    >>> example, that means that you can't do this thing with a
    >>> std::auto_ptr. Or a stream.

    >
    >> Even more interesting.

    >
    >> Given the following declaration:

    >
    >> void foo(int& ref);

    >
    >> Could you explain how ref argument can possibly be
    >> copy-initialized please?

    >
    > There's more to it that Alf revealed. (It wouldn't be the C++
    > standard if it were that simple.) It's copy initialization, so
    > the rules for copy initialization apply. The rule that requires
    > a copy constructor when copy initialization is used only applies
    > when initializing a reference with an rvalue (and this is the
    > only time copies are allowed). If the initializer is an lvalue,
    > everything is fine---otherwise, things like:
    > int i;
    > int& ri = i;
    > would have somewhat unexpected semantics.


    I've been looking at 8.5 Initializers now. My understanding is that
    because that form of initialization which is used for function arguments
    is called copy initialization, it implies that a copy constructor is
    required regardless of whether an argument is a reference that can be
    bound directly. It also says that copy elision is a permissible
    optimization, but does not require it.

    My intuitive expectation is that implied by the spirit of C++: you don't
    pay for what you don't use. Applied to the initialization of reference
    function arguments I would expect it to require the copy constructor
    only when it is actually used. Oh, well ;)

    Alf and Johannes report that initialization of references does not
    require a copy constructor in the C++0x standard. I am glad that they
    elaborated this case :)

    --
    Max
     
    Maxim Yegorushkin, Oct 26, 2009
    #15
  16. Mc Lauren Series

    James Kanze Guest

    On Oct 26, 11:02 pm, Maxim Yegorushkin <>
    wrote:
    > On 26/10/09 17:47, James Kanze wrote:
    > > On Oct 26, 4:07 pm, Maxim Yegorushkin<>
    > > wrote:


    [...]
    > >>> The argument passing is defined as copy initialization. And
    > >>> in C++98 the implementation is allowed to make any number of
    > >>> copies of an rvalue actual argument passed to 'T const&'
    > >>> formal argument, or for any copy initialization. Which means
    > >>> that the type must provide a suitable copy constructor. For
    > >>> example, that means that you can't do this thing with a
    > >>> std::auto_ptr. Or a stream.


    > >> Even more interesting.


    > >> Given the following declaration:


    > >> void foo(int& ref);


    > >> Could you explain how ref argument can possibly be
    > >> copy-initialized please?


    > > There's more to it that Alf revealed. (It wouldn't be the
    > > C++ standard if it were that simple.) It's copy
    > > initialization, so the rules for copy initialization apply.
    > > The rule that requires a copy constructor when copy
    > > initialization is used only applies when initializing a
    > > reference with an rvalue (and this is the only time copies
    > > are allowed). If the initializer is an lvalue, everything
    > > is fine---otherwise, things like:
    > > int i;
    > > int& ri = i;
    > > would have somewhat unexpected semantics.


    > I've been looking at 8.5 Initializers now. My understanding is
    > that because that form of initialization which is used for
    > function arguments is called copy initialization, it implies
    > that a copy constructor is required regardless of whether an
    > argument is a reference that can be bound directly.


    What part of 8.5 exactly? In §8.5/12,13, it says that the
    initializer must be copied, but the initializer here would be
    the T&, the reference. (That does have "interesting"
    implications concerning the lifetime of temporaries, but I'm
    pretty sure that that isn't intentional.) §8.5.3/5 is quite
    clear: "[...]-- If the initializer expression [...]-- is an
    lvalue[...] then the reference is bound directly to the
    initializer expression."

    > It also says that copy elision is a permissible optimization,
    > but does not require it.


    Yes, but since we're talking here about copying the reference, I
    don't think that it's too relevant. References are copiable,
    regardless of what they refer to. The possible problem
    regarding copy is the lifetime of the temporary. Given
    something like:
    int const& ri = 3;
    , the temporary containing the 3 has its lifetime extended to
    that of the reference it initializes. If the reference it
    initializes is a temporary, which is then copied to initialize
    ri, this doesn't help us much.

    As I said, I don't think this was intended, and I none of the
    compilers I know implement it this way.

    > My intuitive expectation is that implied by the spirit of C++:
    > you don't pay for what you don't use. Applied to the
    > initialization of reference function arguments I would expect
    > it to require the copy constructor only when it is actually
    > used. Oh, well ;)


    You don't want the legality of a program changed by whether the
    compiler does some optional optimization or not.

    > Alf and Johannes report that initialization of references does
    > not require a copy constructor in the C++0x standard. I am
    > glad that they elaborated this case :)


    I've still got to examine the new text. The reason for the rule
    (I think) is for things like:

    struct S { A a; B b; }; // A and B class types...
    S f();

    B const& rb = f().b;

    What should be the lifetime of the S returned by f(). I'd argue
    that the current text of the standard says that its lifetime
    must end at the end of the full expression. But the only way to
    end it, while extending the lifetime of the B temporary bound to
    rb, is to copy it out of the S object. (A quick read of the
    text in N2914---a recent, but perhaps not the latest,
    draft---seems a bit ambiguous. None of the enumerated points
    seems to cover this case.)

    --
    James Kanze
     
    James Kanze, Oct 28, 2009
    #16
  17. Mc Lauren Series

    James Kanze Guest

    On Oct 26, 3:36 pm, Maxim Yegorushkin <>
    wrote:
    > Victor Bazarov wrote:
    > > Maxim Yegorushkin wrote:


    [...]
    > >> Given the following declaration:


    > >> void foo(int& ref);


    > >> Could you explain how ref argument can possibly be
    > >> copy-initialized please?


    > > I am guessing the same way 'r2' is a "copy" of 'r1' here:


    > > int a = 42;
    > > int &r1 = a;
    > > int &r2 = r1;


    > > :)


    > Very well, this is what I wanted to hear. ;)


    > In this case no copy constructor is required to
    > copy-initialize a reference to non-const. By induction, the
    > same should hold true for references to const (although they
    > can be initialized with r-values, but only if necessary).


    Except when the standard explicitly says it is necessary. When
    binding a reference to an rvalue, the present standard gives the
    compiler the liberty of either binding the rvalue object
    directly, or binding a copy of the rvalue object (which is
    necessary in certain cases to respect object lifetime); since it
    doesn't want the legality of a program to depend on
    implementation choices, it requires an accessible copy
    constructor in all cases.

    The next version of the standard is more explicit, requiring the
    copy explicitly in some cases (i.e. when it would be necessary
    for lifetime of object reasons), and forbidding it in others;
    when it is forbidden, the compiler is not allowed to make the
    copy, and no copy constructor is required.

    > Hence, the above lvalue function template is well-formed.


    > Comeau online compiles lvalue(std::istringstream(...)) just fine.


    It shouldn't, according to C++03. The next version of the
    standard will allow it, however. (I think, too, that a lot of
    current compilers also allow it---g++ being the major
    exception.)

    --
    James Kanze
     
    James Kanze, Oct 29, 2009
    #17
  18. Mc Lauren Series

    Pavel Guest

    James Kanze wrote:
    > On Oct 26, 11:02 pm, Maxim Yegorushkin <>
    > wrote:
    >> On 26/10/09 17:47, James Kanze wrote:
    >>> On Oct 26, 4:07 pm, Maxim Yegorushkin<>
    >>> wrote:

    >
    > [...]
    >>>>> The argument passing is defined as copy initialization. And
    >>>>> in C++98 the implementation is allowed to make any number of
    >>>>> copies of an rvalue actual argument passed to 'T const&'
    >>>>> formal argument, or for any copy initialization. Which means
    >>>>> that the type must provide a suitable copy constructor. For
    >>>>> example, that means that you can't do this thing with a
    >>>>> std::auto_ptr. Or a stream.

    >
    >>>> Even more interesting.

    >
    >>>> Given the following declaration:

    >
    >>>> void foo(int& ref);

    >
    >>>> Could you explain how ref argument can possibly be
    >>>> copy-initialized please?

    >
    >>> There's more to it that Alf revealed. (It wouldn't be the
    >>> C++ standard if it were that simple.) It's copy
    >>> initialization, so the rules for copy initialization apply.
    >>> The rule that requires a copy constructor when copy
    >>> initialization is used only applies when initializing a
    >>> reference with an rvalue (and this is the only time copies
    >>> are allowed). If the initializer is an lvalue, everything
    >>> is fine---otherwise, things like:
    >>> int i;
    >>> int& ri = i;
    >>> would have somewhat unexpected semantics.

    >
    >> I've been looking at 8.5 Initializers now. My understanding is
    >> that because that form of initialization which is used for
    >> function arguments is called copy initialization, it implies
    >> that a copy constructor is required regardless of whether an
    >> argument is a reference that can be bound directly.

    >
    > What part of 8.5 exactly? In §8.5/12,13, it says that the
    > initializer must be copied, but the initializer here would be
    > the T&, the reference. (That does have "interesting"
    > implications concerning the lifetime of temporaries, but I'm
    > pretty sure that that isn't intentional.) §8.5.3/5 is quite
    > clear: "[...]-- If the initializer expression [...]-- is an
    > lvalue[...] then the reference is bound directly to the
    > initializer expression."
    >
    >> It also says that copy elision is a permissible optimization,
    >> but does not require it.

    >
    > Yes, but since we're talking here about copying the reference, I
    > don't think that it's too relevant. References are copiable,
    > regardless of what they refer to. The possible problem
    > regarding copy is the lifetime of the temporary. Given
    > something like:
    > int const& ri = 3;
    > , the temporary containing the 3 has its lifetime extended to
    > that of the reference it initializes. If the reference it
    > initializes is a temporary, which is then copied to initialize
    > ri, this doesn't help us much.
    >
    > As I said, I don't think this was intended, and I none of the
    > compilers I know implement it this way.
    >
    >> My intuitive expectation is that implied by the spirit of C++:
    >> you don't pay for what you don't use. Applied to the
    >> initialization of reference function arguments I would expect
    >> it to require the copy constructor only when it is actually
    >> used. Oh, well ;)

    >
    > You don't want the legality of a program changed by whether the
    > compiler does some optional optimization or not.
    >
    >> Alf and Johannes report that initialization of references does
    >> not require a copy constructor in the C++0x standard. I am
    >> glad that they elaborated this case :)

    >
    > I've still got to examine the new text. The reason for the rule
    > (I think) is for things like:
    >
    > struct S { A a; B b; }; // A and B class types...
    > S f();
    >
    > B const& rb = f().b;
    >
    > What should be the lifetime of the S returned by f(). I'd argue
    > that the current text of the standard says that its lifetime
    > must end at the end of the full expression. But the only way to
    > end it, while extending the lifetime of the B temporary bound to
    > rb, is to copy it out of the S object.

    Why does the lifetime of B temporary has to be extended? Do you imply
    this because the lifetime of rb extends beyond the one of S temporary?

    > (A quick read of the
    > text in N2914---a recent, but perhaps not the latest,
    > draft---seems a bit ambiguous. None of the enumerated points
    > seems to cover this case.)
    >
    > --
    > James Kanze
     
    Pavel, Oct 31, 2009
    #18
  19. Mc Lauren Series

    James Kanze Guest

    On Oct 31, 6:45 pm, Pavel
    <> wrote:
    > James Kanze wrote:


    [...]
    > > I've still got to examine the new text. The reason for the rule
    > > (I think) is for things like:


    > > struct S { A a; B b; }; // A and B class types...
    > > S f();


    > > B const& rb = f().b;


    > > What should be the lifetime of the S returned by f(). I'd
    > > argue that the current text of the standard says that its
    > > lifetime must end at the end of the full expression. But
    > > the only way to end it, while extending the lifetime of the
    > > B temporary bound to rb, is to copy it out of the S object.


    > Why does the lifetime of B temporary has to be extended?


    Because the standard says so. When a reference is initialized
    with a temporary, the lifetime of that temporary is extended to
    match that of the reference. (See §12.2.)

    > Do you imply this because the lifetime of rb extends beyond
    > the one of S temporary?


    Yes. The standard clearly requires that the lifetime of the
    temporary bound to the reference be extended to that of the
    reference. It also clearly requires that the lifetime of the
    temporary S terminate at the end of the full expression. The
    current standard allows a copy here, and the compilers I've
    checked in the past (and the one I have access to at present:
    VC++) do make a copy. The current draft forbids the copy here,
    while not changing any of the other requirements; I'm not sure
    how they expect this to be implemented.

    --
    James Kanze
     
    James Kanze, Nov 2, 2009
    #19
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ellarco
    Replies:
    5
    Views:
    4,540
    Ellarco
    Sep 24, 2003
  2. Victor Bazarov
    Replies:
    2
    Views:
    4,282
    =?ISO-8859-1?Q?Ney_Andr=E9_de_Mello_Zunino?=
    Nov 12, 2004
  3. Mr. SweatyFinger

    why why why why why

    Mr. SweatyFinger, Nov 28, 2006, in forum: ASP .Net
    Replies:
    4
    Views:
    912
    Mark Rae
    Dec 21, 2006
  4. Mr. SweatyFinger
    Replies:
    2
    Views:
    2,004
    Smokey Grindel
    Dec 2, 2006
  5. Replies:
    3
    Views:
    463
    Michael DOUBEZ
    Nov 14, 2007
Loading...

Share This Page