Aku
Aku

Reputation: 200

C++ change behavior of template methods with traits

I have a template and I have the methods T get(int i) and set(int i, T val). I have to make traits class which change not behavior but the arguements which set and get have.

template<typename T,int Roz>
class Wektor{
public:
 T tab[Roz];
 T get(int i)
 {
     return tab[i];
 }
 void set(T val,int i)
 {
     tab[i]=val;
 }
 }

So the traits class have to change the get and set. If T is int or double we gets parametr by copy int

 int get(int i);
 void set(int val,int i);

double

 double get(int i);
 void set(double val,int i);

for others types:

T* get(int i);
void set(T* val,int i);

That we must do in traits not by specialization of template.

So I write tratis like this:

template<typename T,int Roz>
class traitsWektor
{
public:
T tab[Roz];
T get(int i)
{
    return tab[i];
}
void set(T val,int i)
{
    tab[i]=val;
}
}

So here I stuck. I think i should make

template<typename T, int Roz>
class Wektor : public traitsWektor<T,Roz>

But i am not sure is that right and is still tratis.

Upvotes: 0

Views: 289

Answers (3)

hansmaad
hansmaad

Reputation: 18905

I am not sure how you want to implement set(T*,int). But for get you might want to try this

template<typename T, size_t Roz>
class Wektor
{
public:
    template<typename U=T>
    typename std::enable_if<std::is_arithmetic<U>::value, U>::type 
        Get(size_t n)
    { 
        return tab[n];
    }

    template<typename U=T>
    typename std::enable_if<!std::is_arithmetic<U>::value, U*>::type 
        Get(size_t n)
    { 
        return &tab[n];
    }

    T tab[Roz];
};

Upvotes: 0

Arne Mertz
Arne Mertz

Reputation: 24576

You should separate the class template (Wektor) and the parameter type deduction:

template <class T>
struct WektorParamTraits {
  typedef T const& type;

  //or if you might have different types as getter return type and setter arg
  typedef T const& getterReturn;
  typedef T const& setterArg;
};

In that case, T is the "default" type for your getter/setter arguments. Specialize it for any type you need. The class definition now should look like follows:

template<typename T,int Roz>
class Wektor{
  T tab[Roz]; //make member variables private
public:
  typename WektorParamTraits<T>::getterReturn get(int i) //const?
  {
    return tab[i];
  }

  void set(typename WektorParamTraits<T>::setterArg val,int i)
  {
    tab[i]=val;
  }
};

Update: as was noted in the comments, you might need to define other implementations for get and set e.g. if your return type is a pointer. There are several different approaches to do that:

  1. define functions in the traits to correctly convert between tab[i] and the argument/return value.
  2. If it's only about pointers and non-pointers, provide two versions of the getters and setters and use std::enable_if with std::is_pointer and whatever else is needed to disable one of them.
  3. Use the simple class definition you posted here and specialize it for the few types that don't use the usual references. Any further functionality should go into an unspecialized subclass.

Approach 2 would be very verbose and hard to read. Approach 1 would be verbose as well, and since you would delegate nearly everything except the array definition to that traits class, you could as well use approach 3 since that is not too far away.

Upvotes: 4

I think this template may help you:

template<typename T>
class traits
{
public:
    typedef T * result;
};

template<>
class traits<int>
{
public:
    typedef int result;
};

template<>
class traits<double>
{
public:
    typedef double result;
};


traits<int>::result; // is int.
traits<char>::result; // is char *.

Upvotes: 0

Related Questions