Pregunta

Estoy usando libgc, un recolector de basura para C y C ++. Para hacer que los contenedores STL sean recolectables, se debe usar gc_allocator.

En lugar de escribir

std::vector<MyType> 

uno tiene que escribir

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

¿Podría haber una manera de definir algo como

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

Lo comprobé hace algún tiempo y descubrí que no era posible. Pero podría haber estado equivocado o podría haber otra forma de evitarlo.

Definir mapas de esta manera es particularmente desagradable.

std::map<Key,Val> 

se convierte

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

EDITAR: después de probar el uso de macro descubrí que el siguiente código lo rompe:

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

La coma dentro de la definición de tipo con plantilla se interpreta como un separador de argumento macro.

Entonces parece que la clase / estructura interna es la mejor solución.

Aquí hay un ejemplo de cómo se hará en 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; 
¿Fue útil?

Solución

Puede usar alias de tipo con plantilla C ++ 11 usando using p. como este

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

Nota: Sé que esta es una pregunta antigua, pero dado que tiene muchos votos a favor y como aparece en los resultados de búsqueda, pensé que merecía una respuesta actualizada.

Otros consejos

No puede usar una " typedef typedef " ;, pero puede usar una clase / estructura de conveniencia con un tipo interno:

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

y luego usar en su código

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

Y algo similar para el mapa:

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

EDITAR - @Vijay: No sé si hay otra solución posible, así es como lo haría; una macro podría darle una notación más compacta, pero personalmente no me gustaría:

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

EDITAR - @chmike: ¡Tenga en cuenta que la solución TypeHelper no requiere que redefina los constructores!

Puede heredar públicamente:

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
};

Esto resuelve su problema por completo. El tipo derivado se puede usar en todas partes donde se puede usar el tipo base, y no hay sobrecarga de implementación con ningún compilador decente.

El hecho de que std :: vector tenga un destructor no virtual puede conducir a un comportamiento indefinido según el estándar C ++ si alguna vez intenta eliminar una variable de clase derivada a través de un puntero a la variable de clase base.

En el mundo real, esto no debería importar en este caso particular: la clase derivada no tiene nada nuevo agregado en comparación con la clase base y, por lo tanto, el destructor de la clase derivada simplemente llama al destructor de la clase base. Proceda con paranoia, puerto con cuidado de todos modos.

Si nunca asigna estas variables de clase en el montón (y es típico asignar variables vectoriales en la pila y como miembros de otras clases), el problema del destructor no virtual no le afecta.

Se puede hacer con un MACRO, si está dispuesto a llevar su compilador a sus límites. Lo hice mientras implementaba equivalentes de C ++ para & Quot; Future & Quot de Java; y " Llamable " clases Nuestra biblioteca utiliza objetos contados por referencia, por lo que & Quot; Referencia & Lt; T & Gt; & Quot; es en sí misma una clase de plantilla donde " T " deriva de " 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>>

La belleza de esto es que la Macro hace exactamente lo que quieres de un & "; template typedef &"; la desventaja es que no puedes usar & "; < !> lt; > " para su (s) parámetro (s) de tipo y no hay inferencia de tipo.

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) { .... }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top