This discussion is archived
3 Replies Latest reply: Jan 7, 2013 1:26 PM by Steve_Clamage RSS

Undefined symbol for operator in namespace

982694 Newbie
Currently Being Moderated
If I compile the below into an object file and output it symbol table the operator+ is undefined.
namespace U
{
   struct X
   {
      void foo();
   };

   X& operator+( U::X& );

   struct Y
   {
     void bar();
   };
}

using namespace U;

X& operator+( X& x )
{
   return x;
}

void X::foo()
{
}

void Y::bar()
{
   X x;

   x.foo();

   operator+(x);

   return;
}
% nm -CA z.o


z.o:

z.o: [Index]   Value      Size    Type  Bind  Other Shndx   Name

z.o: [2]        |         0|       0|SECT |LOCL |0    |9      |
z.o: [3]        |         0|       0|SECT |LOCL |0    |8      |
z.o: [4]        |         0|       0|OBJT |LOCL |0    |6      |Bbss.bss
z.o: [5]        |         0|       0|OBJT |LOCL |0    |3      |Ddata.data
z.o: [6]        |         0|       0|OBJT |LOCL |0    |5      |Dpicdata.picdata
z.o: [7]        |         0|       0|OBJT |LOCL |0    |4      |Drodata.rodata
z.o: [8]        |         0|       0|FUNC |GLOB |0    |UNDEF  |U::X&U::operator+(U::X&)
                                                       [__1cBU2s6Frn0ABX__2_]
z.o: [11]       |        16|      36|FUNC |GLOB |0    |2      |U::X&operator+(U::X&)
                                                       [__1c2s6FrnBUBX__2_]
z.o: [10]       |        72|      24|FUNC |GLOB |0    |2      |void U::X::foo()
                                                       [__1cBUBXDfoo6M_v_]
z.o: [9]        |       112|      40|FUNC |GLOB |0    |2      |void U::Y::bar()
                                                       [__1cBUBYDbar6M_v_]
z.o: [1]        |         0|       0|FILE |LOCL |0    |ABS    |z.cc
However, if I prefix the operator with the namespace (even though the using namespace is already stated), then it looks ok. Is this a bug?
X& U::operator+( X& x )
{
   return x;
}
% nm -CA z.o


z.o:

z.o: [Index]   Value      Size    Type  Bind  Other Shndx   Name

z.o: [2]        |         0|       0|SECT |LOCL |0    |9      |
z.o: [3]        |         0|       0|SECT |LOCL |0    |8      |
z.o: [4]        |         0|       0|OBJT |LOCL |0    |6      |Bbss.bss
z.o: [5]        |         0|       0|OBJT |LOCL |0    |3      |Ddata.data
z.o: [6]        |         0|       0|OBJT |LOCL |0    |5      |Dpicdata.picdata
z.o: [7]        |         0|       0|OBJT |LOCL |0    |4      |Drodata.rodata
z.o: [10]       |        16|      36|FUNC |GLOB |0    |2      |U::X&U::operator+(U::X&)
                                                       [__1cBU2s6Frn0ABX__2_]
z.o: [9]        |        72|      24|FUNC |GLOB |0    |2      |void U::X::foo()
                                                       [__1cBUBXDfoo6M_v_]
z.o: [8]        |       112|      40|FUNC |GLOB |0    |2      |void U::Y::bar()
                                                       [__1cBUBYDbar6M_v_]
z.o: [1]        |         0|       0|FILE |LOCL |0    |ABS    |z.cc
  • 1. Re: Undefined symbol for operator in namespace
    Steve_Clamage Pro
    Currently Being Moderated
    The difference in behavior is not a compiler bug. Consider this code:
    namespace U {
        void foo();
    }
    void foo() { } // <---
    It declares function U::foo and defines function ::foo. These are different functions.

    If you change the marked line to
    void U::foo() { }
    or if you put that line in namespace U,
    namespace U {
        void foo() { }
    }
    the definition now applies to the declared function.

    The way code in namespaces interacts with other code, and the effects on function overloading in particular, can be somewhat confusing. This might be a good time to review namespaces in a C++ textbook that covers advanced topics.
  • 2. Re: Undefined symbol for operator in namespace
    982694 Newbie
    Currently Being Moderated
    Are functions in namespaces treated differently to operators?

    In my example, the definition of X::foo() does not need to be prefixed with U:: since we are stating the
    using namspace U;
    
    void X::foo()
    {
    }
    However, the definition of
    X& operator+( X&)
    does need to be prefixed with U:: in order to make it refer to the same one as in the declaration ... (even with the using namespace U;)
    using namspace U;
    
    X& U::operator+( X&)
    Edited by: 979691 on Jan 5, 2013 2:41 PM

    Edited by: 979691 on Jan 5, 2013 2:43 PM

    Edited by: 979691 on Jan 5, 2013 2:46 PM
  • 3. Re: Undefined symbol for operator in namespace
    Steve_Clamage Pro
    Currently Being Moderated
    Operator functions are functions and follow the same rules as any non-operator function. The only thing special is that you can use operator notation to call them as well as using function notation.

    Let's take a simpler example that does not use operators. Fasten your seat belt; the ride is a little rough.
    namespace U {
       struct X
       {
          void foo();
       };
       void zz();
    }
    
    using namespace U;
    
    void X::foo() { } // matches U::X::foo
    
    void zz() { } // does not match U::zz
    For the definition of X::foo, the using-declaration for namespace U allows U to be searched. In looking up the qualified name X::foo in its definition, first the name X must be found as the name of a namespace, type, or template. It is found as a type name, and X has a matching declaration for foo. The definition at global scope therefore matches U::X::foo.

    For the definition of zz (or operator+ in your example), a different rule for names in a namespace applies. The C++ standard, section 7.3.1.2 paragraph 2 says that a namespace member can be defined outside its namespace, but only if explicitly qualified (a using-directive doesn't help). A definition of an unqualified name does not match a declaration in a different namespace. (This rule does not apply to X::foo because that is a qualified name.)

    These points are a bit subtle. When using namespaces, it is often best to stick with very basic usage. I would suggest
    - Define a namespace member in the namespace where it is declared. You can re-open a namespace if necessary to define that member later.
    - Avoid using-directives ("using namespace foo;"). The name lookup issues are complicated compared to individual using-declarations ("using foo::bar;"), and you risk pollution by names you did not expect to see.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points