std::operator<<(basic_ostream&, type) vs. std::basic_ostream::operator(type)... ?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Martin T.

    #1

    std::operator<<(basic_ostream&, type) vs. std::basic_ostream::operator(type)... ?

    Hello.

    I tried to overload the operator<< for implicit printing of wchar_t
    string on a char stream.
    Normally using it on a ostream will succeed as
    std::operator<< <std::char_trai ts<char>
    >(std::basic_os tream<char,std: :char_traits<ch ar & _Ostr={...}, ___)
    will be called.

    However, I am using the boost::format library that internally makes use
    of a string stream to store the formatted string. There:
    std::basic_ostr eam<char,std::c har_traits<char ::operator<<(__ _)
    will always be called.

    On what basis will the compiler choose which kind of operator<< will be
    called??

    (see test code below)

    thanks.
    br,
    Martin

    test code:
    ###############
    #include <iostream>
    #include <fstream>
    #include <sstream>
    using namespace std;

    // Output wchar_t* strings on char streams instead of formatting as
    void* ...
    ostream& operator<<(ostr eam& os, const wchar_t* c_ptr) {
    return os << "(TYPE:wchar_t* )"; // placeholder
    }

    // Boost.Format library
    #include <boost/format.hpp>

    ////////////////////////////////////////
    int main(int argc, char* argv[])
    {
    ostringstream ostr;
    ostream& o = ostr;

    o << "\nTest of ostream << operator ..." << endl;
    wchar_t* wstr = L"Hello world!";
    o << "Output of wchar_t* -- " << wstr << endl;
    // CALL STACK ...
    // (2) opov.exe!std::o perator<<<std:: char_traits<cha r>
    >(std::basic_os tream<char,std: :char_traits<ch ar & _Ostr={...}, const
    char * _Val=0x0042f860 ) Line 747 C++
    // (1)
    opov.exe!operat or<<(std::basic _ostream<char,s td::char_traits <char &
    os={...}, const wchar_t * c_ptr=0x0042f8f 0) Line 6 + 0xe bytes C++
    // (0) opov.exe!main(i nt argc=1, char * * argv=0x00356828 ) Line 17 +
    0x26 bytes C++

    o << "\nTest of boost-library ostream << operator ..." << endl;
    o << "Boost formatted wchar_t* -- " << boost::str(boos t::format("%1%" )
    % wstr) << endl;
    // CALL STACK ...
    // (6) msvcp80d.dll!st d::basic_ostrea m<char,std::cha r_traits<char>
    >::operator<<(c onst void * _Val=0x00433a54 ) Line 456 C++
    // (5)
    opov.exe!boost: :io::detail::pu t_last<char,std ::char_traits<c har>,wchar_t
    *>(std::basic_o stream<char,std ::char_traits<c har & os={...}, wchar_t
    * const & x=0x00433a54) Line 98 + 0x11 bytes C++
    // (4)
    opov.exe!boost: :io::detail::pu t<char,std::cha r_traits<char>, std::allocator< char>,wchar_t
    * const &>(wchar_t * const & x=0x00433a54, const
    boost::io::deta il::format_item <char,std::char _traits<char>,s td::allocator<c har>
    & specs={...},
    std::basic_stri ng<char,std::ch ar_traits<char> ,std::allocator <char &
    res="",
    boost::io::basi c_altstringbuf< char,std::char_ traits<char>,st d::allocator<ch ar>
    & buf={...}, std::locale * loc_p=0x0000000 0) Line 150 + 0x2c bytes C++
    // (3)
    opov.exe!boost: :io::detail::di stribute<char,s td::char_traits <char>,std::all ocator<char>,wc har_t
    * const
    &>(boost::basic _format<char,st d::char_traits< char>,std::allo cator<char>
    & self={...}, wchar_t * const & x=0x00433a54) Line 242 + 0x3f bytes C++
    // (2)
    opov.exe!boost: :io::detail::fe ed<char,std::ch ar_traits<char> ,std::allocator <char>,wchar_ t
    * const
    &>(boost::basic _format<char,st d::char_traits< char>,std::allo cator<char>
    & self={...}, wchar_t * const & x=0x00433a54) Line 251 + 0xd bytes C++
    // (1)
    opov.exe!boost: :basic_format<c har,std::char_t raits<char>,std ::allocator<cha r>
    >::operator%<wc har_t *>(wchar_t * const & x=0x00433a54) Line 64 +
    0xd bytes C++
    // (0) opov.exe!main(i nt argc=1, char * * argv=0x00356828 ) Line 53 C++

    // As can be seen on (5) the parameter (now called x) is of type wchar_t*
    // However, the basic_ostream operator<<(void *) will be called.

    cout << ostr.str();
    }
    ############### ###
  • James Kanze

    #2
    Re: std::operator&l t;&lt;(basic_os tream&amp;, type) vs. std::basic_ostr eam::operator(t ype)... ?

    On Mar 6, 5:38 pm, "Martin T." <0xCDCDC...@gmx .atwrote:
    I tried to overload the operator<< for implicit printing of wchar_t
    string on a char stream.
    Normally using it on a ostream will succeed as
    std::operator<< <std::char_trai ts<char>
    >(std::basic_os tream<char,std: :char_traits<ch ar & _Ostr={...}, ___)
    will be called.
    However, I am using the boost::format library that internally makes use
    of a string stream to store the formatted string. There:
    std::basic_ostr eam<char,std::c har_traits<char ::operator<<(__ _)
    will always be called.
    On what basis will the compiler choose which kind of
    operator<< will be called??
    Overload resolution on the set of visible functions.

    You have to be very careful here with user defined << operators
    on basic types. When << is invoked for a standard type from
    within a template, only std:: will be searched at the point of
    instantiation, so if the << wasn't defined at the point of
    definition, it won't be found.
    (see test code below)
    test code:
    ###############
    #include <iostream>
    #include <fstream>
    #include <sstream>
    using namespace std;
    // Output wchar_t* strings on char streams instead of formatting as
    void* ...
    ostream& operator<<(ostr eam& os, const wchar_t* c_ptr) {
    return os << "(TYPE:wchar_t* )"; // placeholder
    }
    // Boost.Format library
    #include <boost/format.hpp>
    Except that here, you've declared (and defined, but that doesn't
    matter) the operator before including the header. So even in a
    template, the compiler should find your declaration, and use it.
    (Unless, of course, boost::format was exported---but I get the
    same results as you with g++, which doesn't support export.)

    If I put the << operator in namespace std (illegal, and
    undefined behavior, but you can often get away with it), the
    code works (even if the declaration is moved after the include
    of boost/format.hpp), but my understanding of the standard is
    that this should not be necessary if the declaration precedes
    the template definition (which, of course, is in the file
    boost/format.hpp).

    It seems weird to me, too.

    --
    James Kanze (GABI Software) email:james.kan ze@gmail.com
    Conseils en informatique orientée objet/
    Beratung in objektorientier ter Datenverarbeitu ng
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

    Comment

    • Martin T.

      #3
      Re: std::operator&l t;&lt;(basic_os tream&amp;, type) vs. std::basic_ostr eam::operator(t ype)... ?

      James Kanze wrote:
      On Mar 6, 5:38 pm, "Martin T." <0xCDCDC...@gmx .atwrote:
      >(snipped)
      >
      >On what basis will the compiler choose which kind of
      >operator<< will be called??
      >
      Overload resolution on the set of visible functions.
      >
      You have to be very careful here with user defined << operators
      on basic types. When << is invoked for a standard type from
      within a template, only std:: will be searched at the point of
      instantiation, so if the << wasn't defined at the point of
      definition, it won't be found.
      >
      Ah ok. This kindof makes sense. Thanks for pointing it out explicitly.

      >(see test code below)
      >
      >test code:
      >############## #
      >#include <iostream>
      >#include <fstream>
      >#include <sstream>
      >using namespace std;
      >
      >// Output wchar_t* strings on char streams instead of formatting as
      >void* ...
      >ostream& operator<<(ostr eam& os, const wchar_t* c_ptr) {
      > return os << "(TYPE:wchar_t* )"; // placeholder
      >}
      >
      >// Boost.Format library
      >#include <boost/format.hpp>
      >
      Except that here, you've declared (and defined, but that doesn't
      matter) the operator before including the header. So even in a
      template, the compiler should find your declaration, and use it.
      (Unless, of course, boost::format was exported---but I get the
      same results as you with g++, which doesn't support export.)
      >
      If I put the << operator in namespace std (illegal, and
      undefined behavior, but you can often get away with it), the
      code works (even if the declaration is moved after the include
      of boost/format.hpp), but my understanding of the standard is
      that this should not be necessary if the declaration precedes
      the template definition (which, of course, is in the file
      boost/format.hpp).
      >
      It seems weird to me, too.
      >
      Thanks a lot for this explanation!
      I sadly had to give up further experiments for now, as my work time is
      only limited atm. :/

      (The reason I wanted to do this was some functions that return wchar_t*
      but my logging is done in char* and in these cases I will get the
      wchar_t* formatted as void*, which is obv. not what I want, but the
      compiler will not find the code parts where the explicit conversion
      wchar_t->char has been forgotten. (as there exists a conversion from
      wchar_t* to void*) ... grml ...)


      Maybe someone else can clear-up this "weirdness" as it apparently seems
      to happen on g++ (you) and on MSVC8 (VS2005) (me) ...

      br,
      Martin

      Comment

      • James Kanze

        #4
        Re: std::operator&l t;&lt;(basic_os tream&amp;, type) vs. std::basic_ostr eam::operator(t ype)... ?

        On 7 mar, 13:18, "Martin T." <0xCDCDC...@gmx .atwrote:
        James Kanze wrote:
        On Mar 6, 5:38 pm, "Martin T." <0xCDCDC...@gmx .atwrote:
        (snipped)
        Maybe someone else can clear-up this "weirdness" as it apparently seems
        to happen on g++ (you) and on MSVC8 (VS2005) (me) ...
        Yes. I'm curious myself, because it does seem to be
        intentional. Maybe there's something particular in
        boost::format which affects name lookup as well; I didn't have
        time to search it in detail to see, but if so, I can't off hand
        imagine what it could be.

        --
        James Kanze (GABI Software) email:james.kan ze@gmail.com
        Conseils en informatique orientée objet/
        Beratung in objektorientier ter Datenverarbeitu ng
        9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

        Comment

        Working...