namespaces, linkage error, operator overloading

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

    namespaces, linkage error, operator overloading

    I am using Visual C++ 2007 to build the code below. I keep getting
    linkage error. Could someone please tell me what I am doing wrong? The
    code works until I start using namespace for my objects.

    Error 1 error LNK2019: unresolved external symbol "class
    std::basic_ostr eam<char,struct std::char_trait s<char & __cdecl
    graph::operator <<(class std::basic_ostr eam<char,struct
    std::char_trait s<char &,class graph::Node &)" (??6graph@@YAAA V?
    $basic_ostream@ DU?$char_traits @D@std@@@std@@A AV12@AAVNode@0@ @Z)
    referenced in function _main Program.obj

    //Node.h
    #ifndef NODE_H
    #define NODE_H

    #include <string>
    #include <iostream>

    using std::ostream;
    using std::string;

    namespace graph {
    class Node
    {
    friend ostream &operator<<(ost ream &, Node &);
    public:
    Node(void);
    Node(const string id);
    ~Node(void);

    string getId() const;
    void setId(const string &);
    private:
    string id;
    };
    }

    #endif

    //Node.cpp
    #include "Node.h"

    using graph::Node;

    namespace graph {
    Node::Node(void )
    {
    }


    Node::Node(cons t string id) {
    }

    Node::~Node(voi d)
    {
    }

    string Node::getId() const {
    return id;
    }

    void Node::setId(con st string &id) {
    this->id = id;
    }
    }

    ostream &operator<<(ost ream &output, Node &node) {
    output << node.getId();
    return output;
    }

    //Program.cpp
    #include "Node.h"

    using graph::Node;
    using std::cout;
    using std::endl;

    int main() {
    Node a("a");
    Node b("b");

    cout << a << " and " << b << endl;
    }

  • twomers

    #2
    Re: namespaces, linkage error, operator overloading

    #ifndef NODE_H
    #define NODE_H

    #include <string>
    #include <iostream>

    using std::ostream;
    using std::string;

    namespace graph {
    class Node
    {
    public:
    friend ostream &operator<<(ost ream &, Node &);
    Node(void);
    Node(const string id);
    ~Node(void);

    string getId() const;
    void setId(const string &);
    private:
    string id;
    };

    }

    #endif

    //Node.cpp

    using graph::Node;

    namespace graph {
    Node::Node(void )
    {
    }

    Node::Node(cons t string id) {
    }

    Node::~Node(voi d)
    {
    }

    string Node::getId() const {
    return id;
    }

    void Node::setId(con st string &id) {
    this->id = id;
    }

    ostream &operator<<(ost ream &output, Node &node) {
    output << node.getId();
    return output;
    }
    }



    //Program.cpp

    using graph::Node;
    using std::cout;
    using std::endl;

    int main() {
    Node a("a");
    Node b("b");

    cout << a << " and " << b << endl;
    }

    Fixes it.

    Comment

    • jakester

      #3
      Re: namespaces, linkage error, operator overloading

      Could you help to explain what happens by declaring the operator<<
      inside public as opposed to outside? I am using C++, How to Program by
      Deitel/Deitel (3rd edition) as a reference. On page 528, they talk
      about implementation of operator overloading as member versus non-
      member functions. This is their guidance:

      1. (), [], ->, or any assignment operator must be implemented as
      member function
      2. when an operator function is implemented as a member function, the
      leftmost operand must be a class object of the operator's class ... if
      the left operand must be an object of a different class or built-in
      type, this operator function must be implemented as a non-member
      function.

      They specifically state that << and >operators should be implemented
      as non-member functions. Doesn't this mean outside public (as I had in
      the original post)?

      Thanks.

      On Apr 14, 5:14 pm, "twomers" <twom...@gmail. comwrote:
      #ifndef NODE_H
      #define NODE_H
      >
      #include <string>
      #include <iostream>
      >
      using std::ostream;
      using std::string;
      >
      namespace graph {
      class Node
      {
      public:
      friend ostream &operator<<(ost ream &, Node &);
      Node(void);
      Node(const string id);
      ~Node(void);
      >
      string getId() const;
      void setId(const string &);
      private:
      string id;
      };
      >
      }
      >
      #endif
      >
      //Node.cpp
      >
      using graph::Node;
      >
      namespace graph {
      Node::Node(void )
      {
      }
      >
      Node::Node(cons t string id) {
      }
      >
      Node::~Node(voi d)
      {
      }
      >
      string Node::getId() const {
      return id;
      }
      >
      void Node::setId(con st string &id) {
      this->id = id;
      }
      >
      ostream &operator<<(ost ream &output, Node &node) {
      output << node.getId();
      return output;
      }
      >
      }
      >
      //Program.cpp
      >
      using graph::Node;
      using std::cout;
      using std::endl;
      >
      int main() {
      Node a("a");
      Node b("b");
      >
      cout << a << " and " << b << endl;
      >
      }
      >
      Fixes it.

      Comment

      • Gianni Mariani

        #4
        Re: namespaces, linkage error, operator overloading


        jakester wrote:
        I am using Visual C++ 2007 to build the code below. I keep getting
        linkage error. Could someone please tell me what I am doing wrong? The
        code works until I start using namespace for my objects.
        In this case, I'm not sure the compiler is totally compliant, however, I
        don't think the error is the issue.
        >
        Error 1 error LNK2019: unresolved external symbol "class
        std::basic_ostr eam<char,struct std::char_trait s<char & __cdecl
        graph::operator <<(class std::basic_ostr eam<char,struct
        ^^^^^^^^^^^^^^^ ^^^

        Notice the graph:
        std::char_trait s<char &,class graph::Node &)" (??6graph@@YAAA V?
        $basic_ostream@ DU?$char_traits @D@std@@@std@@A AV12@AAVNode@0@ @Z)
        referenced in function _main Program.obj
        >
        //Node.h
        #ifndef NODE_H
        #define NODE_H
        >
        #include <string>
        #include <iostream>
        >
        using std::ostream;
        using std::string;
        notice, this is outside the graph: - In this case I suggest you don't do
        this using in a header.
        >
        namespace graph {
        class Node
        {
        friend ostream &operator<<(ost ream &, Node &);
        OK - friend in this case injects a declaration into the enclosing
        namespace, i.e. graph. But, this probably doesn't do what you think you
        want it to do since operator<< is a template not a straight function.

        BTW - you really want a const Node &
        public:
        Node(void);
        Node(const string id);
        ~Node(void);
        >
        string getId() const;
        // don't have to do this - but it's prolly a good idea to return a
        // const std::string & here.
        void setId(const string &);
        private:
        string id;
        };
        }
        >
        #endif
        >
        //Node.cpp
        #include "Node.h"
        >
        using graph::Node;
        >
        namespace graph {
        Node::Node(void )
        {
        }
        >
        >
        Node::Node(cons t string id) {
        }
        >
        Node::~Node(voi d)
        {
        }
        >
        string Node::getId() const {
        return id;
        }
        >
        void Node::setId(con st string &id) {
        this->id = id;
        }
        }
        >
        This is being defined in the global namespace.
        ostream &operator<<(ost ream &output, Node &node) {
        output << node.getId();
        return output;
        }
        >
        //Program.cpp
        #include "Node.h"
        >
        using graph::Node;
        using std::cout;
        using std::endl;
        >
        int main() {
        Node a("a");
        Node b("b");
        >
        cout << a << " and " << b << endl;
        }
        >

        when I compile your code on gcc I get this :

        friendop1.cpp: In function 'int main()':
        friendop1.cpp:6 9: error: ambiguous overload for 'operator<<' in
        'std::cout << a'
        friendop1.cpp:5 3: note: candidates are: std::ostream&
        operator<<(std: :ostream&, graph::Node&)
        friendop1.cpp:1 1: note: std::ostream&
        graph::operator <<(std::ostream &, graph::Node&)

        Which is more like what I expect but I don't think that's totally right
        either - not sure but it is irrelevant.

        The code at the end of this posting shows somthing that does compile and
        run on gcc (probably will also on VC).

        Some people will object to adding things to the std namespace some
        people will say that this is specifically allowed. I've seen some
        compilers that won't work too well if it's not in the std:: namespace so
        that's why I put it there but it may have been a buggy compiler.


        --------------------------------------------------------------
        #include <iostream>
        #include <string>


        namespace graph {
        class Node;
        }

        namespace std {

        template<
        typename i_char_type,
        class i_traits
        >
        basic_ostream<i _char_type, i_traits>& operator << (
        basic_ostream<i _char_type, i_traits & i_ostream,
        const graph::Node & i_value
        );

        } // end namespace

        namespace graph {
        class Node
        {
        // friend decl
        template<
        typename i_char_type,
        class i_traits
        >
        friend
        std::basic_ostr eam<i_char_type , i_traits>& std::operator << (
        std::basic_ostr eam<i_char_type , i_traits & i_ostream,
        const Node & i_value
        );

        public:
        Node(void);
        Node(const std::string id);
        ~Node(void);

        const std::string & getId() const;
        void setId(const std::string &);
        private:
        std::string id;
        };
        }

        namespace std {

        template<
        typename i_char_type,
        class i_traits
        >
        basic_ostream<i _char_type, i_traits>& operator << (
        basic_ostream<i _char_type, i_traits & i_ostream,
        const graph::Node & i_value
        ) {
        i_ostream << i_value.getId() ;
        return i_ostream;
        }


        } // end namespace


        //#endif

        //Node.cpp
        //#include "Node.h"

        using graph::Node;

        namespace graph {
        Node::Node(void )
        {
        }


        Node::Node(cons t std::string id) :id(id) {
        }

        Node::~Node(voi d)
        {
        }

        const std::string & Node::getId() const {
        return id;
        }

        void Node::setId(con st std::string &id) {
        this->id = id;
        }
        }

        //Program.cpp
        //#include "Node.h"

        using graph::Node;
        using std::cout;
        using std::endl;

        int main() {
        Node a("a");
        Node b("b");

        cout << a << " and " << b << endl;
        }

        Comment

        • James Kanze

          #5
          Re: namespaces, linkage error, operator overloading

          On Apr 14, 11:14 pm, "twomers" <twom...@gmail. comwrote:

          [...]
          namespace graph {
          [...]
          ostream &operator<<(ost ream &output, Node &node) {
          If this declaration compiles, it's time to change compilers,
          fast. It's not, and never has been, legal C++; a member
          operator<< takes only one (explicit) parameter.
          output << node.getId();
          return output;
          }
          }
          --
          James Kanze (Gabi Software) email: james.kanze@gma il.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

          • James Kanze

            #6
            Re: namespaces, linkage error, operator overloading

            On Apr 14, 11:50 pm, Gianni Mariani <gi3nos...@mari ani.wswrote:
            jakester wrote:
            I am using Visual C++ 2007 to build the code below. I keep getting
            linkage error. Could someone please tell me what I am doing wrong? The
            code works until I start using namespace for my objects.
            [...]
            using std::ostream;
            using std::string;
            notice, this is outside the graph: - In this case I suggest
            you don't do this using in a header.
            I agree that I don't like using declarations at global scope,
            especially in a header. But I don't think that it has any
            relationship with his problem.
            namespace graph {
            class Node
            {
            friend ostream &operator<<(ost ream &, Node &);
            OK - friend in this case injects a declaration into the enclosing
            namespace, i.e. graph. But, this probably doesn't do what you think you
            want it to do since operator<< is a template not a straight function.
            His operator<< is not a template. On the other hand, he *has*
            effectively declared a function graph::operator <<. When
            overload resolution choses this function, it will look for an
            implementation in the namespace graph.

            [...]
            This is being defined in the global namespace.
            ostream &operator<<(ost ream &output, Node &node) {
            output << node.getId();
            return output;
            }
            Which means that it is a different function. And that he still
            doesn't have a definition for the friend function in namespace
            graph which he declared in the header.
            //Program.cpp
            #include "Node.h"
            using graph::Node;
            using std::cout;
            using std::endl;
            int main() {
            Node a("a");
            Node b("b");
            cout << a << " and " << b << endl;
            }
            when I compile your code on gcc I get this :
            friendop1.cpp: In function 'int main()':
            friendop1.cpp:6 9: error: ambiguous overload for 'operator<<' in
            'std::cout << a'
            friendop1.cpp:5 3: note: candidates are: std::ostream&
            operator<<(std: :ostream&, graph::Node&)
            friendop1.cpp:1 1: note: std::ostream&
            graph::operator <<(std::ostream &, graph::Node&)
            Which is more like what I expect but I don't think that's totally right
            either - not sure but it is irrelevant.
            Are you sure you compiled the same code? There was no
            "::operator <<( std::ostream&, graph::Node& )" (the first
            candidate g++ mentions above) visible in Program.cpp.

            If you put all of the code in a single file, I'm not 100% sure,
            but I think g++ would be right. Normal name lookup finds the
            global function, and ADL finds the function in the namespace, so
            both are in the overload set (along with a lot of other
            functions from std, which are eliminated because they can't be
            called with the given arguments). In his example, he had two
            source files; graph::operator << was the only version visible in
            the header.

            Note that the name of the friend function graph::operator <<
            isn't actually directly visible in namespace graph; friend name
            injection was removed by the standards committee. But the
            function will be found by ADL. If that's the only function that
            the compiler sees (case in the original code), then that's what
            overload resolution will choose, and since he's not implemented
            it, he gets the error message he saw. If there is also another
            function, with the exact same paramters, then the call is
            ambiguous.
            The code at the end of this posting shows somthing that does compile and
            run on gcc (probably will also on VC).
            Some people will object to adding things to the std namespace some
            people will say that this is specifically allowed.
            It depends on what you add.
            I've seen some
            compilers that won't work too well if it's not in the std:: namespace so
            that's why I put it there but it may have been a buggy compiler.
            --------------------------------------------------------------
            #include <iostream>
            #include <string>
            namespace graph {
            class Node;
            }
            namespace std {
            >
            template<
            typename i_char_type,
            class i_traits
            >
            basic_ostream<i _char_type, i_traits>& operator << (
            basic_ostream<i _char_type, i_traits & i_ostream,
            const graph::Node & i_value
            );
            That's illegal, I think. About the only thing your allowed to
            add are specializations of existing templates, not new
            templates. But why be complicated? If he defines operator<< in
            the namespace graph, in his .cpp, everything should be just
            fine.

            --
            --
            James Kanze (Gabi Software) email: james.kanze@gma il.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

            • James Kanze

              #7
              Re: namespaces, linkage error, operator overloading

              On Apr 14, 11:34 pm, "jakester" <vangj...@googl email.comwrote:
              Could you help to explain what happens by declaring the operator<<
              inside public as opposed to outside?
              First, ignore my previous response to twomers posting; I misread
              namespace for class. (It's late here.)
              I am using C++, How to Program by
              Deitel/Deitel (3rd edition) as a reference. On page 528, they talk
              about implementation of operator overloading as member versus non-
              member functions. This is their guidance:
              1. (), [], ->, or any assignment operator must be implemented as
              member function
              2. when an operator function is implemented as a member function, the
              leftmost operand must be a class object of the operator's class ... if
              the left operand must be an object of a different class or built-in
              type, this operator function must be implemented as a non-member
              function.
              They specifically state that << and >operators should be
              implemented as non-member functions. Doesn't this mean
              outside public (as I had in the original post)?
              Non-member means that they are not members of the class. (A
              friend declaration does not declare a member of the class.)
              They still have to be defined in the correct namespace. Two
              functions with the same names in different namespaces are
              different functions.

              --
              James Kanze (Gabi Software) email: james.kanze@gma il.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

              • Gianni Mariani

                #8
                Re: namespaces, linkage error, operator overloading

                James Kanze wrote:

                ....
                >
                >I've seen some
                >compilers that won't work too well if it's not in the std:: namespace so
                >that's why I put it there but it may have been a buggy compiler.
                >
                >--------------------------------------------------------------
                >#include <iostream>
                >#include <string>
                >
                >namespace graph {
                > class Node;
                >}
                >
                >namespace std {
                >>
                >template<
                > typename i_char_type,
                > class i_traits
                > >
                >basic_ostream< i_char_type, i_traits>& operator << (
                > basic_ostream<i _char_type, i_traits & i_ostream,
                > const graph::Node & i_value
                >);
                >
                That's illegal, I think.
                In my recollection I see 50/50 with responses on that one with no one
                truly convinced that it is legal or illegal. Since you can't
                "specialize " a function (like you can a class), however, specialization
                is accomplished by overlaoding a function. For all intents and
                purposes, overloading is specialization for functions. So, was/is it
                the intent of the standard to not allow overloading ? I don't believe
                I've come across a definitive answer.
                ... About the only thing your allowed to
                add are specializations of existing templates, not new
                templates. But why be complicated? If he defines operator<< in
                the namespace graph, in his .cpp, everything should be just
                fine.
                You're probably right. I remember having problems overloading
                operator<< in different namespaces in the past and what I did above
                solved the problem. I more than likely was a buggy compiler that didn't
                handle argument dependent lookup and the work-around is no longer needed.

                Comment

                • James Kanze

                  #9
                  Re: namespaces, linkage error, operator overloading

                  On Apr 15, 3:26 am, Gianni Mariani <gi3nos...@mari ani.wswrote:
                  James Kanze wrote:
                  ...
                  I've seen some
                  compilers that won't work too well if it's not in the std:: namespace so
                  that's why I put it there but it may have been a buggy compiler.
                  --------------------------------------------------------------
                  #include <iostream>
                  #include <string>
                  namespace graph {
                  class Node;
                  }
                  namespace std {
                  template<
                  typename i_char_type,
                  class i_traits
                  basic_ostream<i _char_type, i_traits>& operator << (
                  basic_ostream<i _char_type, i_traits & i_ostream,
                  const graph::Node & i_value
                  );
                  That's illegal, I think.
                  In my recollection I see 50/50 with responses on that one with no one
                  truly convinced that it is legal or illegal.
                  The standard says it's illegal; there's no doubt about that. In
                  practice, however, I think the probability of it causing
                  problems is about 0.
                  Since you can't "specialize " a function (like you can a
                  class), however, specialization is accomplished by overlaoding
                  a function.
                  The standard is clear: a program may add template
                  specializations to namespace std. Nothing about overloads.
                  Specialization and overloading are two very different things.
                  For all intents and
                  purposes, overloading is specialization for functions.
                  >From where do you get that? For some very specific purposes,
                  specialization and overloading play similar rules. But in
                  general, they are two very different mechanisms, with different
                  rules accross the board.
                  So, was/is it
                  the intent of the standard to not allow overloading ? I don't believe
                  I've come across a definitive answer.
                  I'd say that the actual words in the standar are a definitive
                  answer. If you don't think that that they express the actual
                  intent, a defect report would be in order; to date, there isn't
                  one concerning this point, which means that it seems clear, and
                  means what it seems to mean.
                  ... About the only thing your allowed to
                  add are specializations of existing templates, not new
                  templates. But why be complicated? If he defines operator<< in
                  the namespace graph, in his .cpp, everything should be just
                  fine.
                  You're probably right. I remember having problems overloading
                  operator<< in different namespaces in the past and what I did above
                  solved the problem.
                  And I confused namespace and class in my first reading of his
                  problem. One gets an idea in one's head, and one doesn't see
                  what is actually written. I think it's human nature; at least,
                  I've never met anyone who was immune to it.

                  --
                  James Kanze (Gabi Software) email: james.kanze@gma il.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

                  • Gianni Mariani

                    #10
                    Re: namespaces, linkage error, operator overloading

                    James Kanze wrote:
                    On Apr 15, 3:26 am, Gianni Mariani <gi3nos...@mari ani.wswrote:
                    ....
                    >For all intents and
                    >purposes, overloading is specialization for functions.
                    >
                    >>From where do you get that?
                    I'm saying (or intending on saying) what you're ...

                    .... For some very specific purposes,
                    specialization and overloading play similar rules.
                    .... saying here.

                    .... But in
                    general, they are two very different mechanisms, with different
                    rules accross the board.
                    Yes. That's the point.


                    >
                    >So, was/is it
                    >the intent of the standard to not allow overloading ? I don't believe
                    >I've come across a definitive answer.
                    >
                    I'd say that the actual words in the standar are a definitive
                    answer. If you don't think that that they express the actual
                    intent, a defect report would be in order; to date, there isn't
                    one concerning this point, which means that it seems clear, and
                    means what it seems to mean.
                    Ok - it probably needs to be expressed as a defect report because of the
                    confusion. I also don't see there ever being a problem to overload into
                    the std:: namespace as a way of extending support for user types.

                    Comment

                    • jakester

                      #11
                      Re: namespaces, linkage error, operator overloading

                      On Apr 14, 8:05 pm, "James Kanze" <james.ka...@gm ail.comwrote:
                      On Apr 14, 11:14 pm, "twomers" <twom...@gmail. comwrote:
                      >
                      [...]
                      >
                      namespace graph {
                      >
                      [...]
                      >
                      ostream &operator<<(ost ream &output, Node &node) {
                      >
                      If this declaration compiles, it's time to change compilers,
                      fast. It's not, and never has been, legal C++; a member
                      operator<< takes only one (explicit) parameter.
                      >
                      output << node.getId();
                      return output;
                      }
                      }
                      >
                      --
                      James Kanze (Gabi Software) email: james.ka...@gma il.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
                      In my reference book, they say something similar to what you are
                      saying too (overloading operators as member function should not have 2
                      operands). I am quite confused. But the code does compile with VC++
                      and g++. This observation adds much to my confusion.

                      Comment

                      • James Kanze

                        #12
                        Re: namespaces, linkage error, operator overloading

                        jakester wrote:
                        On Apr 14, 8:05 pm, "James Kanze" <james.ka...@gm ail.comwrote:
                        On Apr 14, 11:14 pm, "twomers" <twom...@gmail. comwrote:
                        [...]
                        namespace graph {
                        This is what I misread.
                        [...]
                        ostream &operator<<(ost ream &output, Node &node) {
                        If this declaration compiles, it's time to change compilers,
                        fast. It's not, and never has been, legal C++; a member
                        operator<< takes only one (explicit) parameter.
                        output << node.getId();
                        return output;
                        }
                        }
                        In my reference book, they say something similar to what you are
                        saying too (overloading operators as member function should not have 2
                        operands). I am quite confused. But the code does compile with VC++
                        and g++. This observation adds much to my confusion.
                        The problem is simply that I misread the code, and took a
                        namespace for a class. Overloaded binary operators take one
                        operand if a member, two if a free function. In namespace
                        scope, they are free functions, so two operands are in order.

                        I'm afraid my posting just added to the confusion. Namespaces
                        and classes have nothing to do with one another.

                        With regards to your original code: a friend declaration does
                        *not* declare a member, but rather a function in the enclosing
                        namespace. Which means, of course, that you have to define the
                        function in the enclosing namespace; otherwise, you're defining
                        some other function.

                        --
                        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...