Question

I'm using libgc, a garbage collector for C and C++. To make STL containers garbage collectible one must use the gc_allocator.

Instead of writing

std::vector<MyType> 

one has to write

std::vector<MyType,gc_allocator<MyType> >

Could there be a way to define something like

template<class T> typedef std::vector<T,gc_allocator<T> > gc_vector<T>;

I checked some time ago and found out it was not possible. But I may have been wrong or there might be another way around.

Defining maps in this way is particularly unpleasing.

std::map<Key,Val> 

becomes

std::map<Key,Val, std::less<Key>, gc_allocator< std::pair<const Key, Val> > >

EDIT: After trying the use of macro I found out the following code breaks it:

#define gc_vector(T) std::vector<T, gc_allocator<T> >
typedef gc_vector( std::pair< int, float > ) MyVector;

The comma inside the templated type definition is interpreted as a macro argument separator.

So it seems the inner class/struct is the best solution.

Here is an example on how it will be done in C++0X

// standard vector using my allocator
template<class T>
using gc_vector = std::vector<T, gc_allocator<T> >;

// allocates elements using My_alloc
gc_vector <double> fib = { 1, 2, 3, 5, 8, 13 };

// verbose and fib are of the same type
vector<int, gc_vector <int>> verbose = fib; 
Was it helpful?

Solution

You can use C++11 templated type aliasing using using e.g. like this

template <typename T>
using gc_vector = std::vector<T, gc_allocator<T>>;

Note: I know this is an old question but since it has quite many upvotes and as it turns up in search results I thought it deserved an updated answer.

OTHER TIPS

You cannot use a "templated typedef", but you can use a convenience class/struct with an inner type:

template<typename T>
struct TypeHelper{
    typedef std::vector<T,gc_allocator<T> > Vector;
};

and then use in your code

TypeHelper<MyType>::Vector v;
TypeHelper<MyType>::Vector::iterator it;

And something similar for the map:

template<typename K,typename V>
struct MapHelper{
    typedef std::map<K, V, gc_allocator<K,V> > Map;
};

EDIT - @Vijay: I don't know if there's another possible workaround, that's how I would do it; a macro might give you a more compact notation, but personally I wouldn't like it:

#define GCVECTOR(T) std::vector<T,gc_allocator<T> >

EDIT - @chmike: Please note that the TypeHelper solution does not require you to redefine constructors!

You can publicly inherit:

template<class T>
class gc_vector<T> : public std::vector<T, gc_allocator<T> >
{
    public:
    // You'll have to redeclare all std::vector's constructors here so that
    // they just pass arguments to corresponding constructors of std::vector
};

This solves your problem completely. The derived type can be used everywhere where the base type can be used, and there's no implementation overhead with any decent compiler.

The fact that std::vector has non-virtual destructor might lead to undefined behaviour according to C++ standard if you ever try to delete a derived class variable through a pointer to base class variable.

In real world this shouldn't matter in this particular case - the derived class has nothing new added compared to the base class and therefore the destructor for the derived class just calls the destructor for the base class. Proceed with paranoia, port carefully anyway.

If you never allocate this class variables on heap (and it's typical to allocate vector variables on stack and as members of other classes) the non-virtual destructor problem doesn't affect you.

It can be done with a MACRO, if you're willing to push your compiler to its limits. I did it while implementing C++ equivalents for Java's "Future" and "Callable" classes. Our library uses reference-counted objects, so "Reference<T>" is itself a template class where "T" derives from "ReferencedObject".

1. Create your template Classes. Mine are:

    template<typename T>
    class Callable {
    private:

    public:
        virtual T Call() = 0;
    };

    template<typename T> CountedFuture : public ReferencedObject {
    private:
       Callable<T>* theTask;
       T            theResult;

    public:
       T Get() { 
          // Run task if necessary ...
          if(task) {
             theResult = theTask->Call();
             delete theTask;
          }
          return theResult;
       }
    };

2. In the application code I'm using references, so I define the macro:

   #define Future(T) Reference<CountedFuture<T>>

The beauty of this is that is that the Macro does exactly what you'd want from a "template typedef", the downsides being that you can't use "<>" for your type parameter(s) and there is no type inference.

3. I can now use the Macro wherever I would use a template, like in functions:

   Future(char*) DoSomething() { ... }
   bool          TestSomething(Future(std::string) f) { .... }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top