Help needed for STL ifstream class

Discussion in 'C++' started by Kira Yamato, Oct 6, 2007.

  1. Kira Yamato

    Kira Yamato Guest

    I've posted this in another thread, but I suppose I should've started a
    new thread for it instead.

    I cannot get the following short program to compile under g++:

    #include <iostream>
    #include <fstream>
    #include <iterator>
    #include <algorithm>

    using namespace std;

    int main(int argc, char **argv)
    {
    copy(istream_iterator<char>(argc >= 2 ? ifstream(argv[1]) : cin),
    // this line won't compile!
    istream_iterator<char>(),
    ostream_iterator<char>(cout));

    return 0;
    }

    The compiler error messages are as followed:

    /usr/include/c++/4.0.0/iosfwd: In copy constructor
    'std::basic_ios<char, std::char_traits<char> >::basic_ios(const
    std::basic_ios<char, std::char_traits<char> >&)':
    /usr/include/c++/4.0.0/bits/ios_base.h:779: error:
    'std::ios_base::ios_base(const std::ios_base&)' is private
    /usr/include/c++/4.0.0/iosfwd:55: error: within this context
    /usr/include/c++/4.0.0/iosfwd: In copy constructor
    'std::basic_istream<char, std::char_traits<char> >::basic_istream(const
    std::basic_istream<char, std::char_traits<char> >&)':
    /usr/include/c++/4.0.0/iosfwd:61: warning: synthesized method
    'std::basic_ios<char, std::char_traits<char> >::basic_ios(const
    std::basic_ios<char, std::char_traits<char> >&)' first required here
    a.cpp: In function 'int main(int, char**)':
    a.cpp:10: warning: synthesized method 'std::basic_istream<char,
    std::char_traits<char> >::basic_istream(const std::basic_istream<char,
    std::char_traits<char> >&)' first required here
    a.cpp:10: error: no matching function for call to
    'std::istream_iterator<char, char, std::char_traits<char>,
    ptrdiff_t>::istream_iterator(std::basic_istream<char,
    std::char_traits<char> >)'
    /usr/include/c++/4.0.0/bits/stream_iterator.h:70: note: candidates are:
    std::istream_iterator<_Tp, _CharT, _Traits,
    _Dist>::istream_iterator(const std::istream_iterator<_Tp, _CharT,
    _Traits, _Dist>&) [with _Tp = char, _CharT = char, _Traits =
    std::char_traits<char>, _Dist = ptrdiff_t]
    /usr/include/c++/4.0.0/bits/stream_iterator.h:66: note:
    std::istream_iterator<_Tp, _CharT, _Traits,
    _Dist>::istream_iterator(std::basic_istream<_CharT, _Traits>&) [with
    _Tp = char, _CharT = char, _Traits = std::char_traits<char>, _Dist =
    ptrdiff_t]
    /usr/include/c++/4.0.0/bits/stream_iterator.h:62: note:
    std::istream_iterator<_Tp, _CharT, _Traits, _Dist>::istream_iterator()
    [with _Tp = char, _CharT = char, _Traits = std::char_traits<char>,
    _Dist = ptrdiff_t]

    Now, I have discovered that if I change the program into the following,
    then it compiles fine:

    #include <iostream>
    #include <fstream>
    #include <iterator>
    #include <algorithm>

    using namespace std;

    int main(int argc, char **argv)
    {
    istream *ifile = argc >= 2 ? new ifstream(argv[1]) : &cin;
    copy(istream_iterator<char>(*ifile),
    istream_iterator<char>(),
    ostream_iterator<char>(cout));

    return 0;
    }

    I know this works, but it would be nice to understand why the original
    version does not work anyway.

    Thank you for your help.

    --

    -kira
    Kira Yamato, Oct 6, 2007
    #1
    1. Advertising

  2. Kira Yamato wrote:
    > I've posted this in another thread, but I suppose I should've started
    > a new thread for it instead.
    >
    > I cannot get the following short program to compile under g++:
    >
    > #include <iostream>
    > #include <fstream>
    > #include <iterator>
    > #include <algorithm>
    >
    > using namespace std;
    >
    > int main(int argc, char **argv)
    > {
    > copy(istream_iterator<char>(argc >= 2 ? ifstream(argv[1]) : cin),


    'istream_iterator's constructor that accepts a stream object takes the
    argument by non-const reference. A non-const reference cannot be bound
    to a temporary. You need to create a separate object of type 'ifstream'
    and then pass it to the 'istream_iterator's constructor.

    > // this line won't compile!
    > istream_iterator<char>(),
    > ostream_iterator<char>(cout));
    >
    > return 0;
    > }
    >
    > The compiler error messages are as followed:
    >
    > [..]


    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 6, 2007
    #2
    1. Advertising

  3. Kira Yamato

    Barry Guest

    Kira Yamato wrote:
    > I've posted this in another thread, but I suppose I should've started a
    > new thread for it instead.
    >
    > I cannot get the following short program to compile under g++:
    >
    > #include <iostream>
    > #include <fstream>
    > #include <iterator>
    > #include <algorithm>
    >
    > using namespace std;
    >
    > int main(int argc, char **argv)
    > {
    > copy(istream_iterator<char>(argc >= 2 ? ifstream(argv[1]) : cin), //
    > this line won't compile!
    > istream_iterator<char>(),
    > ostream_iterator<char>(cout));
    >
    > return 0;
    > }
    >
    > The compiler error messages are as followed:
    >
    > /usr/include/c++/4.0.0/iosfwd: In copy constructor 'std::basic_ios<char,
    > std::char_traits<char> >::basic_ios(const std::basic_ios<char,
    > std::char_traits<char> >&)':
    > /usr/include/c++/4.0.0/bits/ios_base.h:779: error:
    > 'std::ios_base::ios_base(const std::ios_base&)' is private
    > /usr/include/c++/4.0.0/iosfwd:55: error: within this context
    > /usr/include/c++/4.0.0/iosfwd: In copy constructor
    > 'std::basic_istream<char, std::char_traits<char> >::basic_istream(const
    > std::basic_istream<char, std::char_traits<char> >&)':
    > /usr/include/c++/4.0.0/iosfwd:61: warning: synthesized method
    > 'std::basic_ios<char, std::char_traits<char> >::basic_ios(const
    > std::basic_ios<char, std::char_traits<char> >&)' first required here
    > a.cpp: In function 'int main(int, char**)':
    > a.cpp:10: warning: synthesized method 'std::basic_istream<char,
    > std::char_traits<char> >::basic_istream(const std::basic_istream<char,
    > std::char_traits<char> >&)' first required here
    > a.cpp:10: error: no matching function for call to
    > 'std::istream_iterator<char, char, std::char_traits<char>,
    > ptrdiff_t>::istream_iterator(std::basic_istream<char,
    > std::char_traits<char> >)'
    > /usr/include/c++/4.0.0/bits/stream_iterator.h:70: note: candidates are:
    > std::istream_iterator<_Tp, _CharT, _Traits,
    > _Dist>::istream_iterator(const std::istream_iterator<_Tp, _CharT,
    > _Traits, _Dist>&) [with _Tp = char, _CharT = char, _Traits =
    > std::char_traits<char>, _Dist = ptrdiff_t]
    > /usr/include/c++/4.0.0/bits/stream_iterator.h:66: note:
    > std::istream_iterator<_Tp, _CharT, _Traits,
    > _Dist>::istream_iterator(std::basic_istream<_CharT, _Traits>&) [with _Tp
    > = char, _CharT = char, _Traits = std::char_traits<char>, _Dist = ptrdiff_t]
    > /usr/include/c++/4.0.0/bits/stream_iterator.h:62: note:
    > std::istream_iterator<_Tp, _CharT, _Traits, _Dist>::istream_iterator()
    > [with _Tp = char, _CharT = char, _Traits = std::char_traits<char>, _Dist
    > = ptrdiff_t]
    >
    > Now, I have discovered that if I change the program into the following,
    > then it compiles fine:
    >
    > #include <iostream>
    > #include <fstream>
    > #include <iterator>
    > #include <algorithm>
    >
    > using namespace std;
    >
    > int main(int argc, char **argv)
    > {
    > istream *ifile = argc >= 2 ? new ifstream(argv[1]) : &cin;
    > copy(istream_iterator<char>(*ifile),
    > istream_iterator<char>(),
    > ostream_iterator<char>(cout));
    >
    > return 0;
    > }
    >
    > I know this works, but it would be nice to understand why the original
    > version does not work anyway.
    >
    > Thank you for your help.
    >


    As "? :" need the second and third expression to be of the same type

    The first example is trying to cast "ifstream(argv[1])" to "ostream&".
    But "ifstream(argv[1])" is an rvalue, you can't cast it to lvalue,
    Unless "Rvalue Reference" is allowed
    Barry, Oct 6, 2007
    #3
  4. Barry wrote:
    > [..]
    > As "? :" need the second and third expression to be of the same type


    I believe it's not that strict.

    long double a = rand() > 5 ? 42 : 3.14159;

    Here 42 is 'int' and 3.14159 is 'double'. The requirement is that
    the types of the expressions should be such that either the second
    can be converted to the first or vice versa.

    >
    > The first example is trying to cast "ifstream(argv[1])" to "ostream&".


    To 'ostream&'? You mean, to 'istream&', right?

    > But "ifstream(argv[1])" is an rvalue, you can't cast it to lvalue,
    > Unless "Rvalue Reference" is allowed


    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 6, 2007
    #4
  5. Kira Yamato

    Kira Yamato Guest

    On 2007-10-05 22:20:13 -0400, "Victor Bazarov" <> said:

    > Kira Yamato wrote:
    >> I've posted this in another thread, but I suppose I should've started
    >> a new thread for it instead.
    >>
    >> I cannot get the following short program to compile under g++:
    >>
    >> #include <iostream>
    >> #include <fstream>
    >> #include <iterator>
    >> #include <algorithm>
    >>
    >> using namespace std;
    >>
    >> int main(int argc, char **argv)
    >> {
    >> copy(istream_iterator<char>(argc >= 2 ? ifstream(argv[1]) : cin),

    >
    > 'istream_iterator's constructor that accepts a stream object takes the
    > argument by non-const reference. A non-const reference cannot be bound
    > to a temporary.


    I see. So in C++, temporary variables are always treated as const?

    If so, is there a good reason why the C++ designer chose it this way?
    As far as I know, a temporary object lives on the stack, and there
    should be no reason why it should not be modified.

    Thanks.

    --

    -kira
    Kira Yamato, Oct 6, 2007
    #5
  6. Kira Yamato

    Kira Yamato Guest

    On 2007-10-05 20:33:09 -0400, Kira Yamato <> said:

    > I've posted this in another thread, but I suppose I should've started a
    > new thread for it instead.
    >
    > I cannot get the following short program to compile under g++:
    >
    > #include <iostream>
    > #include <fstream>
    > #include <iterator>
    > #include <algorithm>
    >
    > using namespace std;
    >
    > int main(int argc, char **argv)
    > {
    > copy(istream_iterator<char>(argc >= 2 ? ifstream(argv[1]) : cin),
    > // this line won't compile!
    > istream_iterator<char>(),
    > ostream_iterator<char>(cout));
    >
    > return 0;
    > }
    >
    > The compiler error messages are as followed:
    >
    > /usr/include/c++/4.0.0/iosfwd: In copy constructor
    > 'std::basic_ios<char, std::char_traits<char> >::basic_ios(const
    > std::basic_ios<char, std::char_traits<char> >&)':
    > /usr/include/c++/4.0.0/bits/ios_base.h:779: error:
    > 'std::ios_base::ios_base(const std::ios_base&)' is private
    > /usr/include/c++/4.0.0/iosfwd:55: error: within this context
    > /usr/include/c++/4.0.0/iosfwd: In copy constructor
    > 'std::basic_istream<char, std::char_traits<char> >::basic_istream(const
    > std::basic_istream<char, std::char_traits<char> >&)':
    > /usr/include/c++/4.0.0/iosfwd:61: warning: synthesized method
    > 'std::basic_ios<char, std::char_traits<char> >::basic_ios(const
    > std::basic_ios<char, std::char_traits<char> >&)' first required here
    > a.cpp: In function 'int main(int, char**)':
    > a.cpp:10: warning: synthesized method 'std::basic_istream<char,
    > std::char_traits<char> >::basic_istream(const std::basic_istream<char,
    > std::char_traits<char> >&)' first required here
    > a.cpp:10: error: no matching function for call to
    > 'std::istream_iterator<char, char, std::char_traits<char>,
    > ptrdiff_t>::istream_iterator(std::basic_istream<char,
    > std::char_traits<char> >)'
    > /usr/include/c++/4.0.0/bits/stream_iterator.h:70: note: candidates are:
    > std::istream_iterator<_Tp, _CharT, _Traits,
    > _Dist>::istream_iterator(const std::istream_iterator<_Tp, _CharT,
    > _Traits, _Dist>&) [with _Tp = char, _CharT = char, _Traits =
    > std::char_traits<char>, _Dist = ptrdiff_t]
    > /usr/include/c++/4.0.0/bits/stream_iterator.h:66: note:
    > std::istream_iterator<_Tp, _CharT, _Traits,
    > _Dist>::istream_iterator(std::basic_istream<_CharT, _Traits>&) [with
    > _Tp = char, _CharT = char, _Traits = std::char_traits<char>, _Dist =
    > ptrdiff_t]
    > /usr/include/c++/4.0.0/bits/stream_iterator.h:62: note:
    > std::istream_iterator<_Tp, _CharT, _Traits, _Dist>::istream_iterator()
    > [with _Tp = char, _CharT = char, _Traits = std::char_traits<char>,
    > _Dist = ptrdiff_t]


    Just a side comment here: One reason I found STL extremely difficult
    to get into is that because of the extreme difficulty in figuring out
    what the error messages are saying.

    Even after it compiles fine, I can't begin to imagine how difficult it
    is to debug a STL heavy program.

    --

    -kira
    Kira Yamato, Oct 6, 2007
    #6
  7. Kira Yamato

    Kai-Uwe Bux Guest

    Kira Yamato wrote:

    > On 2007-10-05 22:20:13 -0400, "Victor Bazarov" <>
    > said:
    >
    >> Kira Yamato wrote:
    >>> I've posted this in another thread, but I suppose I should've started
    >>> a new thread for it instead.
    >>>
    >>> I cannot get the following short program to compile under g++:
    >>>
    >>> #include <iostream>
    >>> #include <fstream>
    >>> #include <iterator>
    >>> #include <algorithm>
    >>>
    >>> using namespace std;
    >>>
    >>> int main(int argc, char **argv)
    >>> {
    >>> copy(istream_iterator<char>(argc >= 2 ? ifstream(argv[1]) : cin),

    >>
    >> 'istream_iterator's constructor that accepts a stream object takes the
    >> argument by non-const reference. A non-const reference cannot be bound
    >> to a temporary.

    >
    > I see. So in C++, temporary variables are always treated as const?


    No, and Victor did not say that.

    Temporaries cannot be used to initialize non-const references. That does not
    imply that temporaries are const objects. You can call non-const member
    functions on temporaries. For temporaries of class type, that includes even
    the assignment operator (if it is accessible). So, temporaries are by no
    means const (unless you created them const). Moreover, any non-const
    reference returned by a member function (e.g., the assignment operator)
    will happily bind to a non-const reference.

    The following snippet illustrates the first point about temporaries being
    non-const:

    #include <iostream>

    struct demo {

    demo ( void ) {}

    void print ( char const * msg ) {
    std::cout << "non-const: " << msg << '\n';
    }

    void print ( char const * msg ) const {
    std::cout << "const: " << msg << '\n';
    }

    };

    typedef demo const const_demo;

    int main ( void ) {
    demo obj;
    obj.print( "object");
    const_demo c_obj;
    c_obj.print( "const object" );
    demo().print( "temporary" );
    const_demo().print( "const temporary" );
    }



    > If so, is there a good reason why the C++ designer chose it this way?


    It helps avoiding some issues arising from integral promotion. Otherwise, it
    is just a nuisance. For instance, you can do:

    MyClass & operator= ( MyClass const & other ) {
    MyClass( other ).swap( *this );
    return ( *thid );
    }

    but not

    MyClass & operator= ( MyClass const & other ) {
    this->swap( MyClass( other ) );
    return ( *this );
    }


    You also cannot use a temporary to initialize a default non-const parameter:

    void search ( SearchClass & initial_pos = SearchClass() );

    but if you provide a member function

    class SearchClass {
    ...

    SearchClass & me ( void ) {
    return ( *this );
    }

    };

    you can do:

    void search ( SearchClass & initial_pos = SearchClass().me() );

    And for standard classes that do not support a me() method, you could do:

    void grow ( std::vector<int> & the_list =
    ( std::vector<int>() = std::vector<int>() ) );

    Since the assignment operattor returns a non-const reference, the result
    will happily bind to the parameter.

    As you can see, it is not very logical at all.


    The next version of the standard will include r-value references which
    hopefully will put an end to this nonsense.



    > As far as I know, a temporary object lives on the stack, and there
    > should be no reason why it should not be modified.


    There isn't and you can modify temporaries at will. You just cannot bind
    them to non-const references directly.



    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Oct 6, 2007
    #7
  8. Kira Yamato wrote:
    > On 2007-10-05 22:20:13 -0400, "Victor Bazarov"
    > <> said:
    >> Kira Yamato wrote:
    >>> I've posted this in another thread, but I suppose I should've
    >>> started a new thread for it instead.
    >>>
    >>> I cannot get the following short program to compile under g++:
    >>>
    >>> #include <iostream>
    >>> #include <fstream>
    >>> #include <iterator>
    >>> #include <algorithm>
    >>>
    >>> using namespace std;
    >>>
    >>> int main(int argc, char **argv)
    >>> {
    >>> copy(istream_iterator<char>(argc >= 2 ? ifstream(argv[1]) : cin),

    >>
    >> 'istream_iterator's constructor that accepts a stream object takes
    >> the argument by non-const reference. A non-const reference cannot
    >> be bound to a temporary.

    >
    > I see. So in C++, temporary variables are always treated as const?


    No. There is no connection. A non-const reference cannot be bound
    to a temporary. But a temporary is not a constant object.

    > If so, is there a good reason why the C++ designer chose it this way?


    It isn't so.

    > As far as I know, a temporary object lives on the stack, and there
    > should be no reason why it should not be modified.


    Where they live is unspecified.

    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 6, 2007
    #8
  9. Kira Yamato

    Pete Becker Guest

    On 2007-10-05 17:59:37 -1000, Kira Yamato <> said:

    >
    > Just a side comment here: One reason I found STL extremely difficult
    > to get into is that because of the extreme difficulty in figuring out
    > what the error messages are saying.


    Yup. It's hard. It helps to practice: write code with deliberate errors
    and see what your compiler gives you for error messages. In the next
    revision of the standard, "concepts" will improve this situation
    considerably. Template writers will be able to decorate them with
    information about what the template requires from its arguments, so the
    compiler can give better error messages.

    >
    > Even after it compiles fine, I can't begin to imagine how difficult it
    > is to debug a STL heavy program.


    Debugging is usually straightforward. Those layers of templates usually
    collapse into fairly simple code.

    --
    Pete
    Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
    Standard C++ Library Extensions: a Tutorial and Reference
    (www.petebecker.com/tr1book)
    Pete Becker, Oct 6, 2007
    #9
  10. Kira Yamato

    Kira Yamato Guest

    On 2007-10-06 00:46:28 -0400, Kai-Uwe Bux <> said:

    > Kira Yamato wrote:
    >
    >> If so, is there a good reason why the C++ designer chose it this way?

    >
    > It helps avoiding some issues arising from integral promotion. Otherwise, it
    > is just a nuisance. For instance, you can do:
    >
    > MyClass & operator= ( MyClass const & other ) {
    > MyClass( other ).swap( *this );
    > return ( *thid );
    > }
    >
    > but not
    >
    > MyClass & operator= ( MyClass const & other ) {
    > this->swap( MyClass( other ) );
    > return ( *this );
    > }
    >
    >
    > You also cannot use a temporary to initialize a default non-const parameter:
    >
    > void search ( SearchClass & initial_pos = SearchClass() );
    >
    > but if you provide a member function
    >
    > class SearchClass {
    > ...
    >
    > SearchClass & me ( void ) {
    > return ( *this );
    > }
    >
    > };
    >
    > you can do:
    >
    > void search ( SearchClass & initial_pos = SearchClass().me() );
    >
    > And for standard classes that do not support a me() method, you could do:
    >
    > void grow ( std::vector<int> & the_list =
    > ( std::vector<int>() = std::vector<int>() ) );
    >
    > Since the assignment operattor returns a non-const reference, the result
    > will happily bind to the parameter.
    >
    > As you can see, it is not very logical at all.
    >
    >
    > The next version of the standard will include r-value references which
    > hopefully will put an end to this nonsense.
    >
    >
    >
    >> As far as I know, a temporary object lives on the stack, and there
    >> should be no reason why it should not be modified.

    >
    > There isn't and you can modify temporaries at will. You just cannot bind
    > them to non-const references directly.
    >
    >
    >
    > Best
    >
    > Kai-Uwe Bux


    Thank you for your very detailed explanation.

    It's beginning to dawn on me that many rules in C++ can be bent.

    For example, your code above shows a way to "bind" a temporary object
    to a non-const reference (by using the returned value of the operator =
    ).

    In another thread I started last week, someone showed me how to declare
    a const member function that can modify its own member variable without
    using 'volatile' nor 'const_cast'. Essentially, his code was as follow:

    class Obj
    {
    private:
    Obj *that;
    int state;

    public:
    Obj() : that(this), state(0) {}

    void changeMe() const
    {
    that->state++; // changing state!
    }
    };

    --

    -kira
    Kira Yamato, Oct 6, 2007
    #10
  11. Kira Yamato

    Kai-Uwe Bux Guest

    Kira Yamato wrote:

    > On 2007-10-06 00:46:28 -0400, Kai-Uwe Bux <> said:
    >
    >> Kira Yamato wrote:
    >>
    >>> If so, is there a good reason why the C++ designer chose it this way?

    >>
    >> It helps avoiding some issues arising from integral promotion. Otherwise,
    >> it is just a nuisance. For instance, you can do:
    >>
    >> MyClass & operator= ( MyClass const & other ) {
    >> MyClass( other ).swap( *this );
    >> return ( *thid );
    >> }
    >>
    >> but not
    >>
    >> MyClass & operator= ( MyClass const & other ) {
    >> this->swap( MyClass( other ) );
    >> return ( *this );
    >> }
    >>
    >>
    >> You also cannot use a temporary to initialize a default non-const
    >> parameter:
    >>
    >> void search ( SearchClass & initial_pos = SearchClass() );
    >>
    >> but if you provide a member function
    >>
    >> class SearchClass {
    >> ...
    >>
    >> SearchClass & me ( void ) {
    >> return ( *this );
    >> }
    >>
    >> };
    >>
    >> you can do:
    >>
    >> void search ( SearchClass & initial_pos = SearchClass().me() );
    >>
    >> And for standard classes that do not support a me() method, you could do:
    >>
    >> void grow ( std::vector<int> & the_list =
    >> ( std::vector<int>() = std::vector<int>() ) );
    >>
    >> Since the assignment operattor returns a non-const reference, the result
    >> will happily bind to the parameter.
    >>
    >> As you can see, it is not very logical at all.
    >>
    >>
    >> The next version of the standard will include r-value references which
    >> hopefully will put an end to this nonsense.
    >>
    >>
    >>
    >>> As far as I know, a temporary object lives on the stack, and there
    >>> should be no reason why it should not be modified.

    >>
    >> There isn't and you can modify temporaries at will. You just cannot bind
    >> them to non-const references directly.
    >>
    >>
    >>
    >> Best
    >>
    >> Kai-Uwe Bux

    >
    > Thank you for your very detailed explanation.
    >
    > It's beginning to dawn on me that many rules in C++ can be bent.
    >
    > For example, your code above shows a way to "bind" a temporary object
    > to a non-const reference (by using the returned value of the operator =
    > ).


    Be careful when bending the rules :)

    For instance, binding a temporary to a non-const reference is subject to
    livetime issues. The following is not good:

    int_vector & iv = ( int_vector() = int_vector() );

    The reason is that the temporary int_vector is destroyed right away. For
    const-references, the standard makes a special guarantee that the temporary
    that is bound to the reference (which may not be the one you think it is)
    lives as long as the reference.

    The reason that you can use these tricks to bind a temporary to a parameter
    in a function call expression is that the temporary is guaranteed to live
    as long as the maximal enclosing expression. As for initializing the
    default parameter, I am actually not sure (I think I checked it once and
    convinced myself that it is OK, but my memory might play a prank on me).


    > In another thread I started last week, someone showed me how to declare
    > a const member function that can modify its own member variable without
    > using 'volatile'


    you mean 'mutable'

    > nor 'const_cast'. Essentially, his code was as follow:
    >
    > class Obj
    > {
    > private:
    > Obj *that;
    > int state;
    >
    > public:
    > Obj() : that(this), state(0) {}
    >
    > void changeMe() const
    > {
    > that->state++; // changing state!
    > }
    > };


    Now, that is evil (and if the object was actually declared const, it is also
    undefined behavior).


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Oct 6, 2007
    #11
  12. Kira Yamato

    James Kanze Guest

    On Oct 6, 4:49 am, "Victor Bazarov" <> wrote:
    > Barry wrote:
    > > [..]
    > > As "? :" need the second and third expression to be of the same type


    > I believe it's not that strict.


    Not at all. Ignoring the special case where one of the second
    or third expressions is a throw expression, the rule for class
    types is that one one of the types must convert to the other.
    One typical use is initializing a pointer to Base with one of
    two different derived, and this requires an explicit cast, since
    there is no attempt to convert both to some common third type.

    > long double a = rand() > 5 ? 42 : 3.14159;


    > Here 42 is 'int' and 3.14159 is 'double'. The requirement is that
    > the types of the expressions should be such that either the second
    > can be converted to the first or vice versa.


    I'ts a bit more complicated than that:). In the case of
    arithmetic or enumeration types, the "usual arithmetic
    conversions" rule applies. Otherwise, of course, the above
    would be ambiguous: int converts to double, and double converts
    to int.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Oct 6, 2007
    #12
    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. E11
    Replies:
    1
    Views:
    4,699
    Thomas Weidenfeller
    Oct 12, 2005
  2. Armando
    Replies:
    2
    Views:
    7,032
    Martijn Lievaart
    Jan 23, 2004
  3. wtnt
    Replies:
    1
    Views:
    3,024
    Jonathan Turkanis
    Jan 30, 2004
  4. Massimo Soricetti

    (help) Runtime error in ifstream/ios class

    Massimo Soricetti, Jan 13, 2006, in forum: C++
    Replies:
    2
    Views:
    425
    Massimo Soricetti
    Jan 14, 2006
  5. MSP
    Replies:
    9
    Views:
    1,186
    Jerry Coffin
    Sep 9, 2009
Loading...

Share This Page