Yan Gao
Yan Gao

Reputation: 181

C++ questions regards to redefinition error when implement a static member function template?

I try to do implement a static function in cpp source file. Get redefinition error. Can someone help me out? Thanks very much!

DEFINE_MY_STATIC_PTR(B_type)
DEFINE_MY_STATIC_PTR(A_type)

-- error: redefinition

struct A_type : B_type
{}

#define DEFINE_MY_STATIC_PTR( TYPE )\
  template< typename TYPE > \
  My_self_deleting* My_static_ptr<TYPE>::my_self_deleting_ptr( TYPE* ptr ) \
  {  return ptr; } 

template<typename TYPE> 
struct My_static_ptr : My_pointer 
{
    static My_self_deleting*    my_self_deleting_ptr   ( TYPE* );
}

How to do this kind of define properly?

From all the help, I found it should delete the template above. It will become implementation for each TYPE when use.

#define DEFINE_MY_STATIC_PTR( TYPE )\
  My_self_deleting* My_static_ptr<TYPE>::my_self_deleting_ptr( TYPE* ptr ) \
  {  return ptr; } 

DEFINE_MY_STATIC_PTR(B_type)
          error: too few template-parameter-lists

Should I add something more to this macro define?

Yes, add template <>

  #define DEFINE_MY_STATIC_PTR( TYPE )\
  template <>
  My_self_deleting* My_static_ptr<TYPE>::my_self_deleting_ptr( TYPE* ptr ) \
  {  return ptr; } 

Upvotes: 0

Views: 1143

Answers (3)

To extend on why that particular error, when the compiler sees (well, in this case the preprocessor):

DEFINE_MY_STATIC_PTR(B_type)
DEFINE_MY_STATIC_PTR(A_type)

It applies the macro and performs textual replacement of the macro arguments, ending with:

template< typename B_type >
  My_self_deleting* My_static_ptr<B_type>::my_self_deleting_ptr( B_type* ptr )
  {  return ptr; } 

template< typename A_type >
  My_self_deleting* My_static_ptr<A_type>::my_self_deleting_ptr( A_type* ptr )
  {  return ptr; }

While for you A_type and B_type probably mean the types with that name, for the compiler they are just identifiers as T or U. So that code is exactly equivalent to:

template< typename T >
  My_self_deleting* My_static_ptr<T>::my_self_deleting_ptr( T* ptr )
  {  return ptr; } 

template< typename T >
  My_self_deleting* My_static_ptr<T>::my_self_deleting_ptr( T* ptr )
  {  return ptr; } 

And there you have your multiple definitions: You have defined the my_self_deleting_ptr function member of the class template twice in the same translation unit, which is an error, even if both definitions are exactly equivalent.

Upvotes: 0

jopasserat
jopasserat

Reputation: 5920

Basically, the template mechanism can be used to avoid rewriting the same algorithm for different types.
Adding a macro to declare several templates introduces a redefinition of the template.

In your case, the sole declaration of the template method is sufficient. Here is how your code should look like:

// declaration of struct A_type
struct A_type : B_type
{}

// declaration of template class My_static_ptr, of template parameter TYPE
template<typename TYPE> 
struct My_static_ptr : My_pointer 
{
    // declaration of template method my_self_deleting_ptr, of template parameter TYPE
    static My_self_deleting*    my_self_deleting_ptr   ( TYPE* );
}

// definition of template static method my_self_deleting_ptr, of template parameter TYPE
template< typename TYPE >
My_self_deleting* My_static_ptr<TYPE>::my_self_deleting_ptr( TYPE* ptr ) \
{  return ptr; } 

Then you need to instantiate your template with a concrete type, so that you can use it:

// instantiation of the template for A_type, by creating an object My_static_ptr parameterized with A_type
My_static_ptr< A_type > myStaticPointer_of_A_type;

Upvotes: 0

Kerrek SB
Kerrek SB

Reputation: 477040

I'm not entirely sure what you're trying to do, but let me make some general remarks:

You don't have a class, you have a class template. That means, you cannot normally separate the implementation from the definition, as the definition has to be visible at every point where you instantiate the template. So the typical solution would be to put everything in the header:

// header.hpp
template<typename T> 
struct My_static_ptr : My_pointer 
{
  static My_self_deleting * my_self_deleting_ptr(T * p)
  {
     return p;
  }
};

Only in certain, special situations could you consider the alternative of providing a bounded set of explicit template instantiations:

// header.hpp
template<typename T> 
struct My_static_ptr : My_pointer 
{
  static My_self_deleting * my_self_deleting_ptr(T * p);
};

// implementation.cpp
template<typename T> My_self_deleting * My_static_ptr<T>::my_self_deleting_ptr(T * p)
{
  return p;
}
// Only the following specializations are usable in your entire program!
template struct My_static_ptr<int>;
template struct My_static_ptr<double>;
template struct My_static_ptr<Foo>;

Upvotes: 1

Related Questions