Stream operator in namespace masks global stream operator

Discussion in 'C++' started by mrstephengross, May 9, 2007.

  1. Hi folks. I've got a weird situation--gcc doesn't like the folllowing
    code snippet, but I don't know if it's correct or not. Here's the
    situation:

    In the global namespace, I've got a operator<< declared that will send
    a vector<T> to a std::eek:stream.
    In the "outer" namespace, I've got a operator<< declared that will
    send a Thing<T> to a std::eek:stream.
    In the "outer" namespace, I've got a function "foo" that tries to send
    a vector<T> to a std::eek:stream.

    When I try to compile it, gcc complains that there's no match for
    operator<< in the foo function's definition.

    Is this correct? Why is gcc not seeing the global namespace
    operator<< ?

    Thanks,
    --Steve ()

    === test.cpp ===

    #include <iostream>
    #include <vector>

    template<typename T> std::eek:stream & operator<< (std::eek:stream & o,
    const std::vector<T> & v);

    namespace outer {

    template<class T> class Thing { };

    template<typename T> std::eek:stream & operator<< (std::eek:stream & o,
    const Thing<T> & t);

    void foo() { std::vector<double> v; std::cout << v; }

    }

    int main()
    {
    return 0;
    }

    === EOF ===
    mrstephengross, May 9, 2007
    #1
    1. Advertising

  2. mrstephengross

    Fei Liu Guest

    mrstephengross wrote:
    > Hi folks. I've got a weird situation--gcc doesn't like the folllowing
    > code snippet, but I don't know if it's correct or not. Here's the
    > situation:
    >
    > In the global namespace, I've got a operator<< declared that will send
    > a vector<T> to a std::eek:stream.
    > In the "outer" namespace, I've got a operator<< declared that will
    > send a Thing<T> to a std::eek:stream.
    > In the "outer" namespace, I've got a function "foo" that tries to send
    > a vector<T> to a std::eek:stream.
    >
    > When I try to compile it, gcc complains that there's no match for
    > operator<< in the foo function's definition.
    >
    > Is this correct? Why is gcc not seeing the global namespace
    > operator<< ?
    >
    > Thanks,
    > --Steve ()
    >
    > === test.cpp ===
    >
    > #include <iostream>
    > #include <vector>
    >
    > template<typename T> std::eek:stream & operator<< (std::eek:stream & o,
    > const std::vector<T> & v);
    >
    > namespace outer {
    >
    > template<class T> class Thing { };
    >
    > template<typename T> std::eek:stream & operator<< (std::eek:stream & o,
    > const Thing<T> & t);
    >
    > void foo() { std::vector<double> v; std::cout << v; }
    >
    > }
    >
    > int main()
    > {
    > return 0;
    > }
    >
    > === EOF ===
    >


    The compiler is telling you it cannot find a prototype for '<<' in foo.
    The '<<' function hides the '<<' function in global namespace. Try the
    below implementation instead:

    #include <iostream>
    #include <vector>

    template<typename T> std::eek:stream & operator<< (std::eek:stream & o,
    const std::vector<T> & v);

    namespace outer {

    template<class T> class Thing { };

    template<typename T> std::eek:stream & operator<< (std::eek:stream & o,
    const T & t);

    void foo() { std::vector<double> v; std::cout << v; }

    }

    int main()
    {
    return 0;
    }
    Fei Liu, May 9, 2007
    #2
    1. Advertising

  3. mrstephengross

    modemer Guest

    I think compiling is ok but linking has an error with symbol not
    found.

    Just in case if you used gcc, it'd be g++.

    cheers

    On May 9, 10:37 am, mrstephengross <> wrote:
    > Hi folks. I've got a weird situation--gcc doesn't like the folllowing
    > code snippet, but I don't know if it's correct or not. Here's the
    > situation:
    >
    > In the global namespace, I've got a operator<< declared that will send
    > a vector<T> to a std::eek:stream.
    > In the "outer" namespace, I've got a operator<< declared that will
    > send a Thing<T> to a std::eek:stream.
    > In the "outer" namespace, I've got a function "foo" that tries to send
    > a vector<T> to a std::eek:stream.
    >
    > When I try to compile it, gcc complains that there's no match for
    > operator<< in the foo function's definition.
    >
    > Is this correct? Why is gcc not seeing the global namespace
    > operator<< ?
    >
    > Thanks,
    > --Steve ()
    >
    > === test.cpp ===
    >
    > #include <iostream>
    > #include <vector>
    >
    > template<typename T> std::eek:stream & operator<< (std::eek:stream & o,
    > const std::vector<T> & v);
    >
    > namespace outer {
    >
    > template<class T> class Thing { };
    >
    > template<typename T> std::eek:stream & operator<< (std::eek:stream & o,
    > const Thing<T> & t);
    >
    > void foo() { std::vector<double> v; std::cout << v; }
    >
    > }
    >
    > int main()
    > {
    > return 0;
    >
    > }
    >
    > === EOF ===
    modemer, May 9, 2007
    #3
  4. mrstephengross

    James Kanze Guest

    On May 9, 4:37 pm, mrstephengross <> wrote:
    > Hi folks. I've got a weird situation--gcc doesn't like the folllowing
    > code snippet, but I don't know if it's correct or not. Here's the
    > situation:


    > In the global namespace, I've got a operator<< declared that will send
    > a vector<T> to a std::eek:stream.


    Note that you cannot do this reliably. In order for the
    compiler to reliably find the operator, including in template
    code where it occurs in a dependent context, it must be able to
    find it using ADL. Which means that the operator must be in std
    (or the namespace in which T is defined---built-in types are in
    no namespace, however). And you cannot, legally, add things
    like this to std.

    > In the "outer" namespace, I've got a operator<< declared that will
    > send a Thing<T> to a std::eek:stream.
    > In the "outer" namespace, I've got a function "foo" that tries to send
    > a vector<T> to a std::eek:stream.


    > When I try to compile it, gcc complains that there's no match for
    > operator<< in the foo function's definition.


    > Is this correct? Why is gcc not seeing the global namespace
    > operator<< ?


    > === test.cpp ===


    > #include <iostream>
    > #include <vector>


    > template<typename T> std::eek:stream & operator<< (std::eek:stream & o,
    > const std::vector<T> & v);


    > namespace outer {


    > template<class T> class Thing { };


    > template<typename T> std::eek:stream & operator<< (std::eek:stream & o,
    > const Thing<T> & t);


    > void foo() { std::vector<double> v; std::cout << v; }


    > }


    > int main()
    > {
    >
    > }
    > === EOF ===


    G++ is correct. Unqualified lookup stops when it finds the
    name, here, in outer, and doesn't look further. That exposes
    the operator<< in outer, and no other operator<<. ADL kicks in,
    and causes lookup in the namespaces related to the arguments:
    here, std, so the operator<< in std are also added to the
    overload set. There's nothing to cause the compiler to look in
    the global namespace, however. The built-in types are defined
    in no namespace (and can't have any effect on ADL), and not in
    the global namespace.

    Faced with this problem, there are two answers, depending on
    context:

    -- In production code: don't do this. You never, never want to
    overload << on something like std::vector<double> in
    production code. It will introduce subtle coupling, and
    will cause problems in the long run. When you need to
    output a vector, either write function to do it, or use the
    decorator pattern to call operator<< on one of your types.

    -- For quick tests, or playing around: it's formally undefined
    behavior to define this operator in namespace std, but in
    practice, it won't cause any problems, so just go ahead and
    do it:).

    Note that both of the above solutions depend on ADL, and so will
    also work from within a template.

    --
    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, May 10, 2007
    #4
    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. Gianni Mariani
    Replies:
    0
    Views:
    331
    Gianni Mariani
    Jan 13, 2005
  2. lezard

    masks

    lezard, Jun 1, 2005, in forum: C Programming
    Replies:
    4
    Views:
    590
    Michael Wojcik
    Jun 2, 2005
  3. bobrics
    Replies:
    2
    Views:
    707
    Flash Gordon
    Mar 21, 2006
  4. Dave

    shifts and masks

    Dave, Jun 3, 2006, in forum: C Programming
    Replies:
    4
    Views:
    446
    Malcolm
    Jun 4, 2006
  5. Dave

    replace bitfields with shifts and masks

    Dave, Jun 4, 2006, in forum: C Programming
    Replies:
    3
    Views:
    311
    Chris Torek
    Jun 4, 2006
Loading...

Share This Page