开发者

Extra method in template specialization

开发者 https://www.devze.com 2023-02-14 09:29 出处:网络
I\'m trying to write an templated class with some methods/operators etc.. Now when the cl开发者_StackOverflow中文版ass is of an specififc type i would like to have extra append methods specially suite

I'm trying to write an templated class with some methods/operators etc.. Now when the cl开发者_StackOverflow中文版ass is of an specififc type i would like to have extra append methods specially suited for that type which arent there for any other type. I dont' want to copy all the code into an new class.

Example:

template<typename T>
class Buffer
{
    Buffer(const Buffer<Type> &Buffer) : mData(Buffer.mData)
    {               
    }

    Buffer<Type> Clone()
    {
    }

    void Append (T * aData)
    {
    }

    // this one should only be there when Type is an unsigned char
    void Append (wchar_t * aData)
    {
    }

}

is this at all possible?

Greetz, Richard.


Directly this is impossible. Full specialization is full specialization which means you must implement the specialized class from scratch. However I can suggest the following trick:

template<class T>
class CommonFunctionality
{
   //your methods here
};

template<class T>
class MyClass: public CommonFunctionality<T>
{
};

template<>
class MyClass<MyType>:public CommonFunctionality<MyType>
{
  public:
    //your extra method here
};

thanks to Mark's suggestion, here's what you can do with the clone method:

template<class T, class ActualType>
class CommonFunctionality
{
   //your methods here
   ActualType Clone(){...}
};

template<class T>
class MyClass: public CommonFunctionality<T, MyClass<T> >
{
};

template<>
class MyClass<MyType>:public CommonFunctionality<MyType, MyClass<MyType> >
{
  public:
    //your extra method here
};


Use a policy class to manage the interaction with the type, then your class doesn't really have to worry about the type that is passed in, an appropriate policy (and specialization of said policy) can contain all the logic specific to that type.

#include <iostream>
#include <vector>

template <typename T, typename U>
struct append_policy
{
  template <typename BufferType>
  static void append(BufferType& buffer, U type)
  {
    std::cout << "default: append U" << std::endl;
  }
};

template <typename U>
struct append_policy<std::string, U>
{
  template <typename BufferType>
  static void append(BufferType& buffer, U type)
  {
    std::cout << "string: append U" << std::endl;
  }
};

template <>
struct append_policy<std::string, char>
{
  template <typename BufferType>
  static void append(BufferType& buffer, char type)
  {
    std::cout << "string: append char" << std::endl;
  }
};

template <typename T>
struct foo
{
  template <typename U>
  void append(U a)
  {
    append_policy<T, U>::append(buffer, a);
  }

  std::vector<char> buffer;
};

int main(void)
{
  foo<std::string> f;
  std::string test("test");
  f.append(test);
  f.append('C');

  foo<int> f1;
  f1.append(0);

  return 0;
}

EDIT: now allows you to append any type to any type of MyClass, and allows you to override specific combination of types, and potentially throw exceptions in other combinations which you don't want to support.


One way you can achieve is by having Append() out of class Buffer. Something like:

template <typename T>
void Append(Buffer<T>* pBuffer, T* pData);

and have a specialization like this:

template <>
void Append(Buffer<wchat_t>* pBuffer, wchar_t* pData);


Use partial specialization:

// --*-- C++ --*--

#include <cstdio>

template <typename T>
class Buffer
{
public:
    Buffer () {}

    void Append (const T * aData)
    {
        printf ("Data ptr = %p\n", aData);
    }
};

// Special implementation for `wchar_t` case.
template <>
void Buffer<wchar_t>::Append (const wchar_t * aData)
{
    printf ("wchar_t ptr = %p\n", aData);
}

int main ()
{
    Buffer<char> a;
    a.Append (NULL);

    Buffer<wchar_t> b;
    b.Append (NULL);
}


If you want both functions available when T is unsigned char, then do this:

template<typename T>    
struct AddExtraAppend{}; //empty 

template<>              
struct AddExtraAppend<unsigned char> //T=unsigned char,so define a function
{
   void Append (wchar_t * aData)
   {
   }    
};

template<typename T>
class Buffer : AddExtraAppend<T>
{
   void Append (T * aData)
   {
   }    

   //Dont define Append(wchar_t *) here
   //Because if T is unsigned char, it will be inhereted from AddExtraAppend<>
};

This is the basic idea. You can combine it with CRTP to achieve your goal.


However, if you want just one function available, then you can do this.

First write a param<> class template as,

template<typename T> 
struct param { typedef T type; };

template<> //specialization to satisfy your requirement!
struct param<unsigned char> { typedef wchar_t type; };

Then, define just one function (instead of two) as:

void Append (typename param<T>::type * aData)
{
}


You can use

template<class T1, class T2>
struct check_equal;

template<class T1>
struct check_equal<T1, T1> {};

template<typename T>
class Buffer
{
    int mData;
public:
    Buffer(): mData(0) {}
    Buffer(const Buffer<T> &buffer) : mData(buffer.mData) {}

    void Append (T * aData)
    {
    }

    void Append (wchar_t * aData)
    {
        check_equal<T, unsigned char>();
        // ...
    }
};

In that way you can't use Append(wchar_t*) member function if T is not unsigned char, because compiler won't allow it. And if you don't use the method compiler will optimize it, so it won't exist in code.

Check http://www.ideone.com/mh9Rk

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号