Function template has already been defined

This is a discussion on Function template has already been defined within the C++ Programming forums, part of the General Programming Boards category; Can anyone say why I get this error message that indicates that it has been defined twice? The functions in ...

  1. #1
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Posts
    23,029

    Function template has already been defined

    Can anyone say why I get this error message that indicates that it has been defined twice?
    The functions in question are two operators defined inline in the class:

    Code:
    template<typename T, template<int> class thread_safety = ptr_thread_dangerous, int Bits = 32> class mad_shared_ptr
    {
    	//...
    	template<typename lhs_t, typename rhs_t>
    	friend bool operator == (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs)
    	{
    		return (lhs.m_ptr == rhs.m_ptr);
    	}
    
    	template<typename lhs_t, typename rhs_t>
    	friend bool operator != (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs)
    	{
    		return !(lhs == rhs);
    	}
    //...
    }
    When the header containing the template class is included in two source files, it gives me these re-definition errors.
    1>------ Build started, Configuration: Debug Win32 ------
    1>Compiling...
    1>Testing.cpp

    1>Compiling...
    1>CCharacter.cpp

    1>mad_shared_ptr.h(130) : error C2995: 'bool operator ==(const mad_shared_ptr<lhs_t> &,const mad_shared_ptr<rhs_t> &)' : function template has already been defined
    1>mad_shared_ptr.h(130) : see declaration of 'operator =='
    1>ccharacter.cpp(39) : see reference to class template instantiation 'mad_shared_ptr<T>' being compiled
    1> with
    1> [
    1> T=hgeSprite
    1> ]

    1>mad_shared_ptr.h(136) : error C2995: 'bool operator !=(const mad_shared_ptr<lhs_t> &,const mad_shared_ptr<rhs_t> &)' : function template has already been defined
    1>mad_shared_ptr.h(136) : see declaration of 'operator !='

    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
    Both Testing.cpp and CCharacter.cpp includes the header, and the header DOES have inclusion guards.
    I can post the entire class if necessary.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  2. #2
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,265
    Move the operators outside of the class.
    Code:
    template<typename T, template<int> class thread_safety = ptr_thread_dangerous, int Bits = 32> class mad_shared_ptr
    {
    	//...	
    }
    template<typename lhs_t, typename rhs_t>
    	bool operator == (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs)
    	{
    		return (lhs.m_ptr == rhs.m_ptr);
    	}
    
    	template<typename lhs_t, typename rhs_t>
    	bool operator != (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs)
    	{
    		return !(lhs == rhs);
    	}

  3. #3
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Posts
    23,029
    Any reason why?
    Furthermore, I get huge amounts of syntax errors that should not be when I try:
    Code:
    template<typename T, template<int> class thread_safety = ptr_thread_dangerous, int Bits = 32> class mad_shared_ptr
    {
    	template<typename lhs_t, typename rhs_t>
    	friend bool operator == <> (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs);
    
    	template<typename lhs_t, typename rhs_t>
    	friend bool operator != <> (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs);
    }
    
    template<typename lhs_t, typename rhs_t>
    friend bool operator == (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs)
    {
    	return (lhs.m_ptr == rhs.m_ptr);
    }
    
    template<typename lhs_t, typename rhs_t>
    friend bool operator != (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs)
    {
    	return !(lhs == rhs);
    }
    Error 1 error C2: syntax error : missing ';' before '<'
    Error 2 error C2433: '==' : 'friend' not permitted on data declarations
    Error 3 error C2238: unexpected token(s) preceding ';'
    Error 4 error C2988: unrecognizable template declaration/definition
    Error 5 error C2059: syntax error : '<'
    Error 6 error C2238: unexpected token(s) preceding ';'
    Error 7 error C2988: unrecognizable template declaration/definition
    Error 8 error C2059: syntax error : 'return'
    Error 9 error C2334: unexpected token(s) preceding ':'; skipping apparent function body
    Error 10 error C2760: syntax error : expected '{' not ';'
    Warning 11 warning C4346: 'thread_safety<Bits>::Increment' : dependent name is not a type
    Error 12 error C2988: unrecognizable template declaration/definition
    Error 13 error C2059: syntax error : '&'
    Error 14 error C3254: 'mad_shared_ptr<T,thread_safety,Bits>' : class contains explicit override 'Increment' but does not derive from an interface that contains the function declaration
    Error 15 error C2838: 'Increment' : illegal qualified name in member declaration
    Error 16 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
    Warning 17 warning C4183: 'Increment': missing return type; assumed to be a member function returning 'int'
    Error 18 error C2: syntax error : missing ';' before 'void' 146
    Error 19 error C2255: 'friend' : not allowed outside of a class definition
    Error 20 error C2365: '==' : redefinition; previous definition was 'data variable'
    Error 21 error C2904: '==' : name already used for a template in the current scope
    Error 22 error C2255: 'friend' : not allowed outside of a class definition
    Error 23 error C2: syntax error : missing ';' before '<'
    Error 24 error C2433: '==' : 'friend' not permitted on data declarations
    Error 25 error C2238: unexpected token(s) preceding ';'
    Error 26 error C2988: unrecognizable template declaration/definition
    Error 27 error C2059: syntax error : '<'
    Error 28 error C2238: unexpected token(s) preceding ';'
    Error 29 error C2988: unrecognizable template declaration/definition
    Error 30 error C2059: syntax error : 'return'
    Error 31 error C2039: 'this_type_does_not_support_comparisons' : is not a member of 'mad_shared_ptr<T>'
    Error 32 error C2334: unexpected token(s) preceding ':'; skipping apparent function body
    Error 33 error C2760: syntax error : expected '{' not ';'
    Error 34 error C2988: unrecognizable template declaration/definition
    Error 35 error C2059: syntax error : '&'
    Error 36 error C3254: 'mad_shared_ptr<T>' : class contains explicit override 'Increment' but does not derive from an interface that contains the function declaration
    Error 37 error C2838: 'Increment' : illegal qualified name in member declaration
    Error 38 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
    Warning 39 warning C4183: 'Increment': missing return type; assumed to be a member function returning 'int'
    Error 40 error C2: syntax error : missing ';' before 'void'
    Error 41 error C2678: binary '==' : no operator found which takes a left-hand operand of type 'mad_shared_ptr<T>' (or there is no acceptable conversion)
    I'm confused...
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  4. #4
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,265
    You need to drop the friend keyword. I'm not sure if you will still have syntax errors since I can't compile your code. You may need to post the entire class (If it doesn't have a bunch of dependencies) if the problem persists.

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Posts
    23,029
    Oh yes, I forgot those. But they do not help.
    The header requires the following external dependencies (if I didn't forget anything):
    Code:
    #include <windows.h>
    #include <boost/cstdint.hpp>
    #include <memory>
    #include <assert.h>
    #include <boost/type_traits.hpp>
    And the code (copy and paste):
    Code:
    #ifndef MAD_SHARED_PTR_175451_H
    #define MAD_SHARED_PTR_175451_H
    
    const int nullptr = NULL;
    
    template<typename T> T* mad_ptr_clone(const T* pOld) { return smad_ptr_int<T, boost::is_polymorphic<T>::value>::Clone(pOld); }
    
    template<typename T, bool Polymorphic> struct smad_ptr_int
    {
    	static T* Clone(const T* pOld) { return pOld->Clone(); } // IsPolymorphic = yes
    };
    template<typename T> struct smad_ptr_int<T, false>
    {
    	static T* Clone(const T* pOld) { return new T(*pOld); } // IsPolymorphic = no
    };
    
    template<int N> struct ptr_bits { /*typedef current_amount_of_bits_not_supported rf_type;*/ };
    template<> struct ptr_bits<32> { typedef boost::uint32_t rf_type; };
    template<> struct ptr_bits<64> { typedef boost::uint64_t rf_type; };
    
    template<int Bits> class ptr_thread_safe { };
    template<> class ptr_thread_safe<32> 
    {
    public:
    	static void Increment(void* p) { InterlockedIncrement((LONG*)p); }
    	static void Decrement(void* p) { InterlockedDecrement((LONG*)p); }
    };
    template<> class ptr_thread_safe<64> 
    {
    public:
    	static void Increment(void* p) { InterlockedIncrement64((LONGLONG*)p); }
    	static void Decrement(void* p) { InterlockedDecrement64((LONGLONG*)p); }
    };
    template<int Bits> class ptr_thread_dangerous
    {
    public:
    	template<typename T> static void Increment(T* p) { (*p)++; }
    	template<typename T> static void Decrement(T* p) { (*p)--; }
    };
    
    template<typename T, template<int> class thread_safety = ptr_thread_dangerous, int Bits = 32> class mad_shared_ptr
    {
    protected:
    	typedef void (mad_shared_ptr::* bool_type)() const;
    	template<typename T, int Bits> struct sptr
    	{
    		template<typename T> class deleter_base { public: virtual void destroy(T* p) = 0; };
    		template<typename T, typename deleter_t> class deleter: public deleter_base<T>
    		{
    		public:
    			deleter(deleter_t delete_fnc): m_delete_fnc(delete_fnc) { }
    			virtual void destroy(T* p) { m_delete_fnc(p); }
    
    		private:
    			deleter_t m_delete_fnc;
    		};
    
    		sptr(): p(nullptr), RefCount(0), pDeleter(nullptr) { }
    
    		T* p;
    		typename ptr_bits<Bits>::rf_type RefCount;
    		deleter_base<T>* pDeleter;
    	};
    	typedef sptr<T, Bits> ptr_t;
    
    public:
    	mad_shared_ptr(): m_ptr(nullptr) { }
    	template<typename Other> mad_shared_ptr(Other* p): m_ptr(nullptr) { *this = p; }
    	template<typename Other, typename Deleter> mad_shared_ptr(Other* p, Deleter delete_fnc): m_ptr(nullptr)
    	{
    		std::auto_ptr< ptr_t::deleter_base<T> > pDeleter( new ptr_t::deleter<T, Deleter>(delete_fnc) );
    		*this = p;
    		m_ptr->pDeleter = pDeleter.release();
    	}
    	mad_shared_ptr(const mad_shared_ptr& rhs): m_ptr(nullptr) { *this = rhs; }
    	template<typename Other> mad_shared_ptr(const mad_shared_ptr<Other>& rhs): m_ptr(nullptr) { *this = rhs; }
    	~mad_shared_ptr() { DecRefCount(m_ptr); }
    	bool unique() const { return (m_ptr->RefCount == 1); }
    	void make_unique()
    	{
    		if (unique())
    			return;
    		
    		std::auto_ptr<ptr_t> pNewPtr(new ptr_t);
    		pNewPtr->p = mad_ptr_clone(m_ptr->p);
    		pNewPtr->RefCount = 1;
    		pNewPtr->pDeleter = m_ptr->pDeleter;
    		DecRefCount(m_ptr);
    		m_ptr = pNewPtr.release();
    	}
    	void release()
    	{
    		DecRefCount();
    		m_p = nullptr;
    		m_RefCount = nullptr;
    		m_deleter = nullptr;
    	}
    	template<typename Other> mad_shared_ptr& operator = (Other* rhs)
    	{
    		if (m_ptr && rhs == m_ptr->p)
    			return *this;
    
    		ptr_t* pOldPtr = m_ptr;
    		std::auto_ptr<ptr_t> pNewPtr(new ptr_t);
    
    		pNewPtr->p = rhs;
    		pNewPtr->RefCount++;
    		m_ptr = pNewPtr.release();
    
    		DecRefCount(pOldPtr);
    		return *this;
    	}
    	mad_shared_ptr& operator = (const mad_shared_ptr& rhs)
    	{
    		return operator = <T>(rhs);
    	}
    	template<typename Other> mad_shared_ptr& operator = (const mad_shared_ptr<Other>& rhs)
    	{
    		if (rhs == *this)
    			return *this;
    		DecRefCount(m_ptr);
    		m_ptr = rhs.m_ptr;
    		IncRefCount(m_ptr);
    		return *this;
    	}
    	T& operator * () const { assert(m_ptr); return *m_ptr->p; }
    	T* operator -> () const { assert(m_ptr); return m_ptr->p; }
    
    	template<typename lhs_t, typename rhs_t>
    	friend bool operator == <> (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs);
    
    	template<typename lhs_t, typename rhs_t>
    	friend bool operator != <> (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs);
    
    	operator bool_type() const 
    	{
    		return m_ptr && m_ptr->p ? &mad_shared_ptr::this_type_does_not_support_comparisons : nullptr;
        }
    
    protected:
    	void IncRefCount(sptr<T, Bits>* ptr)
    	{
    		thread_safety<Bits>::Increment(&ptr->RefCount);
    	}
    
    	void DecRefCount(sptr<T, Bits>*& ptr)
    	{
    		if (ptr == nullptr)
    			return;
    		thread_safety<Bits>::Decrement(&ptr->RefCount);
    		if (ptr->RefCount == 0)
    		{
    			if (ptr->pDeleter)
    				ptr->pDeleter->destroy(ptr->p);
    			else
    				delete ptr->p;
    			delete ptr;
    			ptr = nullptr;
    		}
    	}
    
    	void this_type_does_not_support_comparisons() const {}
    
    	sptr<T, Bits>* m_ptr;
    };
    
    template<typename lhs_t, typename rhs_t>
    bool operator == (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs)
    {
    	return (lhs.m_ptr == rhs.m_ptr);
    }
    
    template<typename lhs_t, typename rhs_t>
    bool operator != (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs)
    {
    	return !(lhs == rhs);
    }
    
    #endif // MAD_SHARED_PTR_175451_H
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #6
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,415
    "Can anyone say why I get this error message that indicates that it has been defined twice?"

    There error you posted has nothing to do with simple header issues if this is a method defined inside a template class. (You would get different errors... and a lot of them.)

    Play with the extra source I've posted.

    "Move the operators outside of the class."

    That will directly solve nothing, but he may solve this issue as a side effect of moving the definitions. You are allowed to do what he has attempted; he has only done it wrong in some fashion.

    "I'm confused..."

    You did it wrong. See the source...

    "But they do not help."

    Why would it? You are still doing it wrong. Worse, you've already modified your source and may not solve the original problem.

    Also, please learn to reduce your code to the smallest sample that results in the problem you need help with... I've obviously had to remove the Boost stuff and the 64 bit stuff.

    Soma

    Code:
    #include <iostream>
    #include "test.h"
    #include "test2.h"
    
    int main2();
    
    int main()
    {
       test<int> a, b;
       test2<int> c, d;
       a == b;
       c == d;
       main2();
       return(0);
    }
    Code:
    #include <iostream>
    #include "test.h"
    #include "test2.h"
    
    int main2()
    {
       test<int> a, b;
       test2<int> c, d;
       a == b;
       c == d;
       return(0);
    }
    Code:
    template
    <
       unsigned long bits
    >
    struct nothing
    {
    };
    
    template
    <
       typename T,
       template <unsigned long> class ignored = nothing,
       unsigned long bits = 32
    >
    struct test
    {
       template
       <
          typename TN,
          typename UN
       >
       friend bool operator ==
       (
          const test<TN> & lhs,
          const test<UN> & rhs
       )
       {
          std::cout << "test\n";
          return(true);
       }
       template
       <
          typename TN,
          typename UN
       >
       friend bool operator ==
       (
          const test<TN> & lhs,
          const test<UN> & rhs
       )
       {
          std::cout << "test\n";
          return(true);
       }
    };
    Code:
    template
    <
       unsigned long bits
    >
    struct nothing2
    {
    };
    
    template
    <
       typename T,
       template <unsigned long> class ignored = nothing2,
       unsigned long bits = 32
    >
    struct test2;
    
    template
    <
       typename TN,
       typename UN
    >
    bool operator ==
    (
       const test2<TN> & lhs,
       const test2<UN> & rhs
    );
    
    template
    <
       typename T,
       template <unsigned long> class ignored,
       unsigned long bits
    >
    struct test2
    {
       template<typename TN, typename UN>
       friend bool operator == <> (const test2<TN> & lhs, const test2<UN>& rhs);
       private: int i;
    };
    
    template
    <
       typename TN,
       typename UN
    >
    bool operator ==
    (
       const test2<TN> & lhs,
       const test2<UN> & rhs
    )
    {
       std::cout << "test2\n";
       return(lhs.i == rhs.i);
    }
    Code:
    #ifndef MAD_SHARED_PTR_175451_H
    #define MAD_SHARED_PTR_175451_H
    
    #include <windows.h>
    #include <memory>
    #include <assert.h>
    
    
    const int nullptr = NULL;
    
    template<typename T> T* mad_ptr_clone(const T* pOld) {  }
    
    template<typename T, bool Polymorphic> struct smad_ptr_int
    {
    	static T* Clone(const T* pOld) { return pOld->Clone(); } // IsPolymorphic = yes
    };
    template<typename T> struct smad_ptr_int<T, false>
    {
    	static T* Clone(const T* pOld) { return new T(*pOld); } // IsPolymorphic = no
    };
    
    template<int N> struct ptr_bits { /*typedef current_amount_of_bits_not_supported rf_type;*/ };
    template<> struct ptr_bits<32> { typedef unsigned long rf_type; };
    template<> struct ptr_bits<64> { typedef unsigned long long rf_type; };
    
    template<int Bits> class ptr_thread_safe { };
    template<> class ptr_thread_safe<32> 
    {
    public:
    	static void Increment(void* p) { InterlockedIncrement((LONG*)p); }
    	static void Decrement(void* p) { InterlockedDecrement((LONG*)p); }
    };
    template<> class ptr_thread_safe<64> 
    {
    public:
    	static void Increment(void* p) { InterlockedIncrement((LONG*)p); }
    	static void Decrement(void* p) { InterlockedDecrement((LONG*)p); }
    };
    template<int Bits> class ptr_thread_dangerous
    {
    public:
    	template<typename T> static void Increment(T* p) { (*p)++; }
    	template<typename T> static void Decrement(T* p) { (*p)--; }
    };
    
    template<typename T, template<int> class thread_safety = ptr_thread_dangerous, int Bits = 32> class mad_shared_ptr;
    
    template<typename lhs_t, typename rhs_t>
    	bool operator == (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs);
    	
    template<typename lhs_t, typename rhs_t>
    	bool operator != (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs);
    
    template<typename T, template<int> class thread_safety, int Bits> class mad_shared_ptr
    {
    protected:
    	typedef void (mad_shared_ptr::* bool_type)() const;
    	template<typename T, int Bits> struct sptr
    	{
    		template<typename T> class deleter_base { public: virtual void destroy(T* p) = 0; };
    		template<typename T, typename deleter_t> class deleter: public deleter_base<T>
    		{
    		public:
    			deleter(deleter_t delete_fnc): m_delete_fnc(delete_fnc) { }
    			virtual void destroy(T* p) { m_delete_fnc(p); }
    
    		private:
    			deleter_t m_delete_fnc;
    		};
    
    		sptr(): p(nullptr), RefCount(0), pDeleter(nullptr) { }
    
    		T* p;
    		typename ptr_bits<Bits>::rf_type RefCount;
    		deleter_base<T>* pDeleter;
    	};
    	typedef sptr<T, Bits> ptr_t;
    
    public:
    	mad_shared_ptr(): m_ptr(nullptr) { }
    	template<typename Other> mad_shared_ptr(Other* p): m_ptr(nullptr) { *this = p; }
    	template<typename Other, typename Deleter> mad_shared_ptr(Other* p, Deleter delete_fnc): m_ptr(nullptr)
    	{
    		std::auto_ptr< ptr_t::deleter_base<T> > pDeleter( new ptr_t::deleter<T, Deleter>(delete_fnc) );
    		*this = p;
    		m_ptr->pDeleter = pDeleter.release();
    	}
    	mad_shared_ptr(const mad_shared_ptr& rhs): m_ptr(nullptr) { *this = rhs; }
    	template<typename Other> mad_shared_ptr(const mad_shared_ptr<Other>& rhs): m_ptr(nullptr) { *this = rhs; }
    	~mad_shared_ptr() { DecRefCount(m_ptr); }
    	bool unique() const { return (m_ptr->RefCount == 1); }
    	void make_unique()
    	{
    		if (unique())
    			return;
    		
    		std::auto_ptr<ptr_t> pNewPtr(new ptr_t);
    		pNewPtr->p = mad_ptr_clone(m_ptr->p);
    		pNewPtr->RefCount = 1;
    		pNewPtr->pDeleter = m_ptr->pDeleter;
    		DecRefCount(m_ptr);
    		m_ptr = pNewPtr.release();
    	}
    	void release()
    	{
    		DecRefCount();
    		m_p = nullptr;
    		m_RefCount = nullptr;
    		m_deleter = nullptr;
    	}
    	template<typename Other> mad_shared_ptr& operator = (Other* rhs)
    	{
    		if (m_ptr && rhs == m_ptr->p)
    			return *this;
    
    		ptr_t* pOldPtr = m_ptr;
    		std::auto_ptr<ptr_t> pNewPtr(new ptr_t);
    
    		pNewPtr->p = rhs;
    		pNewPtr->RefCount++;
    		m_ptr = pNewPtr.release();
    
    		DecRefCount(pOldPtr);
    		return *this;
    	}
    	mad_shared_ptr& operator = (const mad_shared_ptr& rhs)
    	{
    		return operator = <T>(rhs);
    	}
    	template<typename Other> mad_shared_ptr& operator = (const mad_shared_ptr<Other>& rhs)
    	{
    		if (rhs == *this)
    			return *this;
    		DecRefCount(m_ptr);
    		m_ptr = rhs.m_ptr;
    		IncRefCount(m_ptr);
    		return *this;
    	}
    	T& operator * () const { assert(m_ptr); return *m_ptr->p; }
    	T* operator -> () const { assert(m_ptr); return m_ptr->p; }
    
    	template<typename lhs_t, typename rhs_t>
    	friend bool operator == <> (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs);
    
    	template<typename lhs_t, typename rhs_t>
    	friend bool operator != <> (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs);
    
    	operator bool_type() const 
    	{
    		return m_ptr && m_ptr->p ? &mad_shared_ptr::this_type_does_not_support_comparisons : nullptr;
        }
    
    protected:
    	void IncRefCount(sptr<T, Bits>* ptr)
    	{
    		thread_safety<Bits>::Increment(&ptr->RefCount);
    	}
    
    	void DecRefCount(sptr<T, Bits>*& ptr)
    	{
    		if (ptr == nullptr)
    			return;
    		thread_safety<Bits>::Decrement(&ptr->RefCount);
    		if (ptr->RefCount == 0)
    		{
    			if (ptr->pDeleter)
    				ptr->pDeleter->destroy(ptr->p);
    			else
    				delete ptr->p;
    			delete ptr;
    			ptr = nullptr;
    		}
    	}
    
    	void this_type_does_not_support_comparisons() const {}
    
    	sptr<T, Bits>* m_ptr;
    };
    
    template<typename lhs_t, typename rhs_t>
    bool operator == (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs)
    {
    	return (lhs.m_ptr == rhs.m_ptr);
    }
    
    template<typename lhs_t, typename rhs_t>
    bool operator != (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs)
    {
    	return !(lhs == rhs);
    }
    
    #endif // MAD_SHARED_PTR_175451_H

  7. #7
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,893
    Why do these errors appear? Because you defined a global operator == multiple times.

    Consider:
    A friend function declaration is not a member of the containing class. It's a member of the namespace that contains the class.
    When you do this:
    Code:
    class Foo {
      friend void bar(Foo& f) { f.wooble(); }
      void wooble();
    };
    the situation is simple. You just defined a class Foo, and a global function bar(Foo&) that is a friend of that class.
    Make Foo a template:
    Code:
    template <typename T>
    class Foo {
      friend void bar(Foo& f) { f.wooble(); }
      void wooble();
    };
    Now you've defined a class template Foo with parameter T. Whenever you instantiate this template for a type S, you also define a global function bar(Foo<S>&).

    Finally, look at the code you wrote:
    Code:
    template <typename T>
    class Foo {
      template <typename U>
      friend void bar(Foo<U>& f) { f.wooble(); }
      void wooble();
    };
    Now you've defined a class template Foo with parameter T. Whenever you instantiate this template with a type S, you also define a global function template <U> bar(Foo<U>&).
    Note how you define <U> bar(Foo<U>&) no matter what S is. Instantiate Foo<int>, you get <U> bar(Foo<U>&). Instantiate Foo<std::string>, you also get <U> bar(Foo<U>&).

    That's why the compiler is complaining.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  8. #8
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,265
    Code:
    friend bool operator != <> (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs);
    I'm not sure what that's supposed to do, but it won't compile in gcc. As far as I can tell, my original solution fixes the compile error (at least in gcc it does).

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Posts
    23,029
    Quote Originally Posted by CornedBee View Post
    Now you've defined a class template Foo with parameter T. Whenever you instantiate this template with a type S, you also define a global function template <U> bar(Foo<U>&).
    Note how you define <U> bar(Foo<U>&) no matter what S is. Instantiate Foo<int>, you get <U> bar(Foo<U>&). Instantiate Foo<std::string>, you also get <U> bar(Foo<U>&).

    That's why the compiler is complaining.
    Tricky. Very tricky.
    I get your point, but everytime I would instantiate Foo with the same types, I would get an exact same function again, just like in the above.
    Plus they're marked as inline which should make the compiler ignore multiple definitions, but I'm guessing that somewhere in all this is an exception or rule I don't know.
    But making the left-hand side the type instantiated makes it all work (a solution as per your explanation).

    Quote Originally Posted by bithub View Post
    Code:
    friend bool operator != <> (const mad_shared_ptr<lhs_t>& lhs, const mad_shared_ptr<rhs_t>& rhs);
    I'm not sure what that's supposed to do, but it won't compile in gcc. As far as I can tell, my original solution fixes the compile error (at least in gcc it does).
    Nor will it in VS. That's the tricky part.
    Template friends for operators are tricky. Just have a look:
    [35] Templates ..Updated!.., C++ FAQ Lite
    It specifically also mentions the <> syntax to make the compiler aware it's template friend function we're talking about.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,415
    O_o

    If it doesn't work you have a broken compiler... what version are you two using?

    Try this shorter example that doesn't need all the fluff...

    Soma

    Code:
    #include <iostream>
    
    template
    <
       typename T
    >
    struct test;
    
    template
    <
       typename T,
       typename U
    >
    bool operator ==
    (
       const test<T> & lhs,
       const test<U> & rhs
    );
    
    template
    <
       typename T,
       typename U
    >
    bool operator !=
    (
       const test<T> & lhs,
       const test<U> & rhs
    );
    
    template
    <
       typename T
    >
    struct test
    {
       template
       <
          typename TN,
          typename UN
       >
       friend bool operator ==
       (
          const test<TN> & lhs,
          const test<UN> & rhs
       );
       friend bool operator != <>
       (
          const test<T> & lhs,
          const test<T> & rhs
       );
       private: bool private_m;
    };
    
    template
    <
       typename TN,
       typename UN
    >
    bool operator ==
    (
       const test<TN> & lhs,
       const test<UN> & rhs
    )
    {
       std::cout << __FUNCTION__ << '\n';
       return(lhs.private_m == rhs.private_m);
    }
    
    template
    <
       typename TN,
       typename UN
    >
    bool operator !=
    (
       const test<TN> & lhs,
       const test<UN> & rhs
    )
    {
       std::cout << __FUNCTION__ << '\n';
       return(lhs.private_m != rhs.private_m);
    }
    
    int main()
    {
       test<int> a;
       test<int> b;
       test<double> c;
       a == b;
       b == c;
       a != b;
       // b != c; // private access
       return(0);
    }

  11. #11
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,265
    Try this shorter example that doesn't need all the fluff...
    Your shorter version compiles, but that's just because you fixed the compile error in your first version. btw, this is with gcc 4.2

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Posts
    23,029
    I use Visual Studio 2008.
    There's just something that throws the compiler off. I know the break out the operators and declare them as friends inside the class worked at some time but then it broke, but I don't know why or when or how.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #13
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,415
    "Your shorter version compiles, but that's just because you fixed the compile error in your first version."

    O_o

    o_O

    What?

    You mean, the code I posted to show Elysia the kinds of compiler errors I wanted him to examine/eliminate had errors? (Edit: To clarify, I had no idea why the original source Elysia posted was getting those errors. I assumed that the inline definition inside a class trumped the issue CornedBee explained. To that end, I was trying to broil the problem down to something I could solve.)

    Or are we talking about the code Elysia posted that I altered which shouldn't compile under GCC anyway because it shadows variables, incorrectly casts pointers, and relies on MSVC extensions?

    Anyway, if it compiled here, it wasn't that line by itself that was the problem which is what I was curious about.

    "I know the break out the operators and declare them as friends inside the class worked at some time but then it broke, but I don't know why or when or how."

    When you changed from "friending" a fully instantiated template function to "friending" an actual template I would imagine.

    Soma
    Last edited by phantomotap; 04-13-2009 at 05:10 PM.

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Posts
    23,029
    Quote Originally Posted by phantomotap View Post
    Or are we talking about the code Elysia posted that I altered which shoudln't compile under GCC anyway because it shadows variables, incorrectly casts pointers, and relies on MSVC extensions?
    What? o_O
    Where, when?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  15. #15
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,415
    "What? Where? When?"

    Your original source shadows the template parameter names(A nested template and the containing template both use the entity name `T'.)

    According to my first attempt at compiling the source you've committed the common sin of not telling the compiler where certain names come from. (You need to add the occasional `parent::' or `this->' I imagine.)

    As for the incorrectly cast pointers... I introduced those problems because I don't have Boost or the 64 bit stuff.

    Edit: I just realized I called you "him" again...

    Soma

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Linking problems in Visual Studio
    By h3ro in forum C++ Programming
    Replies: 5
    Last Post: 03-04-2008, 02:39 PM
  2. Replies: 28
    Last Post: 07-17-2006, 12:35 AM
  3. Calling a Thread with a Function Pointer.
    By ScrollMaster in forum Windows Programming
    Replies: 6
    Last Post: 06-10-2006, 09:56 AM
  4. errors initializing D3D
    By Vacation Guy in forum C++ Programming
    Replies: 3
    Last Post: 08-07-2005, 01:20 PM
  5. DLL compiling question
    By Noose in forum Windows Programming
    Replies: 2
    Last Post: 12-16-2004, 07:16 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21