views:

458

answers:

5

I have a container class, we'll call it

template <class T> CVector { ... }

I want to do something different with this class when T is a pointer type, e.g. something along the lines of:

template <class T*> CVector< SomeWrapperClass<T> >;

where SomeWrapperClass is expecting the type of the pointed to thing as its parameter. Unfortunately, this syntax doesn't quite work and with some digging, I haven't found a good way to get something like this working.

Why do it this way? I want to change, in a very large app, how some of our containers work when the type they're specialized on is a pointer vs. not a pointer - and ideally, i'd like to do it without changing the ~1,000 places in the code where there are things like CVector<Object*> vs CVector<int> or some such - and playing games with partial specializations seemed to be the way to go.

Am I on crack here?

+1  A: 

I don't think you can specialize a class using the syntax you describe... I don't know how that could possibly work. What you can do is specialize the class for pointers and re-implement its guts using the wrapper class around the raw pointers. I'm not sure if it will help, but this article describes specializing templates for pointers.

rmeador
Thank you - the article you linked gave me a way to do what i need.
D Garcia
Glad I could help. I don't suppose you'd like to accept my answer, or at least give an upvote, to show appreciation? :)
rmeador
A: 

I don't think templates are quite that flexible.

A very brute force approach would be to specialize for all of your pointer types...which defeats the problem of using templates.

Could you have a different CVector class that is used only for vectors of pointers?

Jesse
If I made a different type, i'd have to go through all the places in the code where the old type was used to flip it over to the new type - less than ideal, i'm looking for a drop in replacement.
D Garcia
+3  A: 

If I understand you correctly, this might do what you want:

template<typename T>
class CVector { ... };

template<typename T>
class CVector<T*> : public CVector< SomeWrapperClass<T> > {
public:
  // for all constructors:
  CVector(...) : CVector< SomeWrapperClass<T> >(...) {
  }
};

It adds an additional layer of inheritance to trick CVector<T*> into being a CVector< SomeWrapperClass<T> >. This might also be useful in case you need to add additional methods to ensure full compatibility between the expected interface for T* and the provided interface for SomeWrapperClass<T>.

sth
Hmm - if I can have the new class be named the same as the old - this might work. If i have to rename the class, i'm back to having to change all the instantiations to a new class, which is work i'm trying to avoid having to do.
D Garcia
It's still just a `CVector<...>`, just that it might inherit from a different `CVector<...>` internally. But users of the class shouldn't care about these internal details, as long as the interface stays compatible.
sth
+1 @Garcia: The solution above should work - you can refer to your use of CVector template as CVector<int> vs CVector<int*> - and the appropriate template will be used (implemented in terms of SomeWrapper<T> vs not)
Faisal Vali
+1  A: 

This works just fine in C++...

#include <iostream>

template <class T>
class CVector
{
public:
    void test() { std::cout << "Not wrapped!\n"; }
};

template <class T>
class CVector<T*>
{
public:
    void test() { std::cout << "Wrapped!\n"; }
};

int main()
{
    CVector<int> i;
    CVector<double> d;
    CVector<int*> pi;
    CVector<double*> pd;
    i.test();
    d.test();
    pi.test();
    pd.test();
}
rlbond
That won't let me change a template parameter conditionally on whether or not it is a pointer - already looked at what boost has. This isn't a case of conditional code - it's a case of conditional typing - the types of things inside the class need to be different based on whether the template parameter is a pointer or not.
D Garcia
A: 

The Boost type traits library can help you achieve this. Check out the is_pointer type trait.

#include <boost/type_traits.hpp>
#include <iostream>
#include <vector>

using namespace std;

template <class T>
class CVector {
  public:
    void addValue(const T& t) {
      values_.push_back(t);
    }

    void print() {
      typedef boost::integral_constant<bool,
        ::boost::is_pointer<T>::value> truth_type;

      for (unsigned int i = 0; i < values_.size(); i++) 
        doPrint(values_[i], truth_type());
    }


  private:
    void doPrint(const T& t, const boost::false_type&) {
      cout << "Not pointer. Value:" << t << endl;
    }

    void doPrint(const T& t, const boost::true_type&) {
      cout << "Pointer. Value: " << *t << endl;
    }

    std::vector<T> values_;
 };


int main() {
  CVector<int> integers;
  integers.addValue(3);
  integers.addValue(5);
  integers.print();

  CVector<int*> pointers;
  int three = 3;
  int five = 5;
  pointers.addValue(&three);
  pointers.addValue(&five);
  pointers.print(); 
}
Kristian