0

I am working with templates and I am getting a duplicate symbol, and I don't know where its coming from.

I have the following class and templates:

class   Example 
{
    public:
        Example(int n) : _n( n ) { }
    
        int     getN() const    { return this->_n; };
        void    setN(int n)         { this->_n = n; }

        bool operator==( Example const & rhs ) const { return (this->_n == rhs._n); }
        bool operator!=( Example const & rhs ) const{ return (this->_n != rhs._n); }
        bool operator>( Example const & rhs ) const { return (this->_n > rhs._n); }
        bool operator<( Example const & rhs ) const { return (this->_n < rhs._n); }
        bool operator>=( Example const & rhs ) const { return (this->_n >= rhs._n); }
        bool operator<=( Example const & rhs ) const { return (this->_n <= rhs._n); }
    
    private:
        int     _n;
};

std::ostream &operator<<(std::ostream &os, Example const &a) {os << a.getN(); return os;}


template <typename T>
void    swap(T &a, T &b)
{
    T   aux;
    
    aux = a;
    a = b;
    b = aux;
}

template <>
void    swap<Example>(Example &a, Example &b)
{
    int     n = a.getN();
    
    a.setN(b.getN());
    b.setN(n);
}

Here everything works smoothly. However, if I try to define some of Example's member functions in a different .cpp (instead of in the header) I get a duplicate symbol error. These are my new files:

whatever.hpp

class   Example 
{
    public:
        Example(int n) : _n( n ) { }
    
        int     getN() const    { return this->_n; };
        void    setN(int n)         { this->_n = n; }

        bool    operator==( Example const & rhs )   const;
        bool    operator!=( Example const & rhs )   const;
        bool    operator>( Example const & rhs )    const;
        bool    operator<( Example const & rhs )    const;
        bool    operator>=( Example const & rhs )   const;
        bool    operator<=( Example const & rhs )   const;
    
    private:
        int     _n;
};

std::ostream &operator<<(std::ostream &os, Example const &a);


template <typename T>
void    swap(T &a, T &b)
{
    T   aux;
    
    aux = a;
    a = b;
    b = aux;
}

template <>
void    swap<Example>(Example &a, Example &b)
{
    int     n = a.getN();
    
    a.setN(b.getN());
    b.setN(n);
}

whatever.cpp

bool            Example::operator==( Example const & rhs )  const { return (this->_n == rhs._n); }
bool            Example::operator!=( Example const & rhs )  const { return (this->_n != rhs._n); }
bool            Example::operator>( Example const & rhs )   const { return (this->_n > rhs._n); }
bool            Example::operator<( Example const & rhs )   const { return (this->_n < rhs._n); }
bool            Example::operator>=( Example const & rhs )  const { return (this->_n >= rhs._n); }
bool            Example::operator<=( Example const & rhs )  const { return (this->_n <= rhs._n); }

std::ostream    &operator<<(std::ostream &os, Example const &a) {os << a.getN(); return os;}

The error I am getting is the following:

duplicate symbol 'void swap<Example>(Example&, Example&)' in:
    main.o
    whatever.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

My main.c is the following:

int main()
{
    Example     obj1(91);
    Example     obj2(124);
    swap(obj1, obj2);
}

Why is this happenng?

kubo
  • 221
  • 1
  • 8
  • 1
    Did you add an include guard in your hpp file, something like #pragma once? – Pepijn Kramer Sep 17 '21 at 12:12
  • 1
    You're correct that templates should only be implemented in header files. Unfortunately that rule doesn't apply for full specializations. Like any other non-template functions they should only be *declared* in the header files and then defined (implemented) in one source file. – Some programmer dude Sep 17 '21 at 12:13
  • 3
    Does this answer your question? [Inlining Template Specialization](https://stackoverflow.com/questions/51987423/inlining-template-specialization) – dewaffled Sep 17 '21 at 12:17
  • You need to declare your `swap` function `inline`. – prapin Sep 17 '21 at 12:19
  • 1
    @prapin A declaration in the header: `template<> void swap(Example& a, Example& b);` and the definition in the `.cpp` would also work fine. – Ted Lyngmo Sep 17 '21 at 12:24

0 Answers0