Шаблонный typedef?
Я использую libgc, сборщик мусора для C и C++. Чтобы сделать контейнеры STL мусорными, нужно использовать gc_allocator.
Вместо того чтобы писать
std::vector<MyType>
надо написать
std::vector<MyType,gc_allocator<MyType> >
Может ли быть способ определить что-то вроде
template<class T> typedef std::vector<T,gc_allocator<T> > gc_vector<T>;
Я проверил некоторое время назад и обнаружил, что это невозможно. Но я мог ошибаться или мог быть другой путь.
Определение карт таким способом особенно неприятно.
std::map<Key,Val>
становится
std::map<Key,Val, std::less<Key>, gc_allocator< std::pair<const Key, Val> > >
РЕДАКТИРОВАТЬ: После попытки использования макроса я обнаружил, что следующий код ломает его:
#define gc_vector(T) std::vector<T, gc_allocator<T> >
typedef gc_vector( std::pair< int, float > ) MyVector;
Запятая внутри определения шаблонного типа интерпретируется как разделитель аргументов макроса.
Так что, кажется, внутренний класс / структура - лучшее решение.
Вот пример того, как это будет сделано в 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;
4 ответа
Вы не можете использовать "шаблонный typedef", но вы можете использовать вспомогательный класс / структуру с внутренним типом:
template<typename T>
struct TypeHelper{
typedef std::vector<T,gc_allocator<T> > Vector;
};
а затем использовать в своем коде
TypeHelper<MyType>::Vector v;
TypeHelper<MyType>::Vector::iterator it;
И что-то похожее на карту:
template<typename K,typename V>
struct MapHelper{
typedef std::map<K, V, gc_allocator<K,V> > Map;
};
РЕДАКТИРОВАТЬ - @Vijay: я не знаю, есть ли другой возможный обходной путь, вот как я бы это сделал; макрос может дать вам более компактную запись, но лично мне это не понравится:
#define GCVECTOR(T) std::vector<T,gc_allocator<T> >
РЕДАКТИРОВАТЬ - @chmike: Обратите внимание, что TypeHelper
Решение не требует переопределения конструкторов!
Вы можете использовать шаблонный псевдоним C++11, используя using
например, вот так
template <typename T>
using gc_vector = std::vector<T, gc_allocator<T>>;
Примечание: я знаю, что это старый вопрос, но поскольку у него довольно много голосов, и, как оказалось, в результатах поиска, я подумал, что он заслуживает обновленного ответа.
Вы можете публично наследовать:
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
};
Это решит вашу проблему полностью. Производный тип может использоваться везде, где может использоваться базовый тип, и нет никаких накладных расходов на реализацию с любым приличным компилятором.
Тот факт, что std::vector имеет не виртуальный деструктор, может привести к неопределенному поведению в соответствии со стандартом C++, если вы когда-нибудь попытаетесь удалить переменную производного класса через указатель на переменную базового класса.
В реальном мире это не должно иметь значения в данном конкретном случае - производный класс не имеет ничего нового по сравнению с базовым классом, и поэтому деструктор для производного класса просто вызывает деструктор для базового класса. Продолжайте с паранойей, портите осторожно в любом случае.
Если вы никогда не размещаете переменные этого класса в куче (и это типично для размещения векторных переменных в стеке и в качестве членов других классов), проблема не виртуального деструктора вас не затронет.
Это можно сделать с помощью MACRO, если вы хотите расширить возможности своего компилятора. Я сделал это во время реализации эквивалентов C++ для классов "Future" и "Callable" в Java. Наша библиотека использует объекты с подсчетом ссылок, поэтому "Reference
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>>
Прелесть этого в том, что макрос делает именно то, что вы хотите от "шаблона typedef", минусом является то, что вы не можете использовать "<>" для параметров типа, и нет никакого вывода типа,
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) { .... }