templated typedef?
Pergunta
Eu estou usando libgc, um coletor de lixo para C e C ++. Para fazer contêineres STL lixo um colecionável deve usar o gc_allocator.
Em vez de escrever
std::vector<MyType>
tem de se escrever
std::vector<MyType,gc_allocator<MyType> >
Poderia haver uma maneira de definir algo como
template<class T> typedef std::vector<T,gc_allocator<T> > gc_vector<T>;
Eu verifiquei há algum tempo e descobri que não era possível. Mas pode ter sido errado ou pode haver outro caminho.
A definição de mapas dessa forma é particularmente desagradável.
std::map<Key,Val>
se torna
std::map<Key,Val, std::less<Key>, gc_allocator< std::pair<const Key, Val> > >
EDIT: Depois de tentar o uso de macro eu descobri os seguintes intervalos de código-lo:
#define gc_vector(T) std::vector<T, gc_allocator<T> >
typedef gc_vector( std::pair< int, float > ) MyVector;
A vírgula dentro da definição de tipo templated é interpretado como um separador de argumentos macro.
Assim, parece que a classe interna / struct é a melhor solução.
Aqui está um exemplo de como isso será feito em 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;
Solução
Você pode usar o C ++ 11 templated tipo aliasing usando using
por exemplo como esta ??p>
template <typename T>
using gc_vector = std::vector<T, gc_allocator<T>>;
. Nota: Eu sei que isto é uma questão de idade, mas já que tem bastante muitos upvotes e como se vê nos resultados de pesquisa achei que merecia uma resposta atualizada
Outras dicas
Você não pode usar uma "typedef templated", mas você pode usar uma classe de conveniência / struct com um tipo interno:
template<typename T>
struct TypeHelper{
typedef std::vector<T,gc_allocator<T> > Vector;
};
e, em seguida, usar em seu código
TypeHelper<MyType>::Vector v;
TypeHelper<MyType>::Vector::iterator it;
E algo semelhante para o mapa:
template<typename K,typename V>
struct MapHelper{
typedef std::map<K, V, gc_allocator<K,V> > Map;
};
EDIT - @Vijay: Eu não sei se há outra solução possível, é assim que eu iria fazê-lo; uma macro pode dar-lhe uma notação mais compacta, mas pessoalmente eu não iria gostar:
#define GCVECTOR(T) std::vector<T,gc_allocator<T> >
! EDIT - @chmike: nota por favor que a solução TypeHelper
não requer que você redefinir construtores
Você pode publicamente herdar:
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
};
Isto resolve o problema completamente. O tipo derivado pode ser usado em todos os lugares onde o tipo de base pode ser usada, e não há nenhuma sobrecarga de implementação com qualquer compilador decente.
O fato de que std :: vector tem destrutor não-virtual pode levar a um comportamento indefinido acordo com o padrão C ++ se você tentar excluir uma variável de classe derivada através de um ponteiro para variável de classe base.
No mundo real isso não deve importar neste caso em particular - a classe derivada tem nada de novo acrescentado em comparação com a classe base e, portanto, o destruidor para a classe derivada apenas chama o destruidor para a classe base. Prossiga com a paranóia, a porta cuidadosamente qualquer maneira.
Se você nunca alocar esses variáveis ??de classe no montão (e é típico para alocar variáveis ??vetor na pilha e como membros de outras classes), o problema destructor não-virtual não afetá-lo.
Isso pode ser feito com uma macro, se você estiver disposto a empurrar o seu compilador para os seus limites. Eu fiz isso durante a implementação equivalentes C ++ para classes "Future" e "resgatáveis" do Java. Nossos objetos contados-referência usa biblioteca, tão "Referência
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>>
A beleza desta é que é que a macro faz exatamente o que você quer de um "typedef modelo", as desvantagens é que você não pode usar "<>" para o seu parâmetro de tipo (s) e não há nenhum tipo de inferência.
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) { .... }