шаблонный 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;
Решение
Вы можете использовать псевдоним шаблонного типа C ++ 11, используя using
например ,вот так
template <typename T>
using gc_vector = std::vector<T, gc_allocator<T>>;
Примечание:Я знаю, что это старый вопрос, но поскольку у него довольно много положительных отзывов и поскольку он появляется в результатах поиска, я подумал, что он заслуживает обновленного ответа.
Другие советы
Вы не можете использовать "шаблонный 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
решение не делает требую от вас переопределения конструкторов!
Вы можете публично наследовать:
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 ++, если вы когда-либо попытаетесь удалить производную переменную класса через указатель на переменную базового класса.
В реальном мире это не должно иметь значения в данном конкретном случае - производный класс не имеет ничего нового, добавленного по сравнению с базовым классом, и поэтому деструктор для производного класса просто вызывает деструктор для базового класса.Продолжайте с паранойей, в любом случае портируйте осторожно.
Если вы никогда не выделяете переменные этого класса в куче (а это типично для выделения векторных переменных в стеке и в качестве членов других классов), проблема с невиртуальным деструктором вас не коснется.
Это можно сделать с помощью МАКРОСА, если вы готовы довести свой компилятор до предела.Я сделал это при реализации эквивалентов C ++ для классов Java "Future" и "Callable".Наша библиотека использует объекты с подсчетом ссылок, поэтому "Reference<T>" сам по себе является шаблонным классом, где "T" является производным от "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>>
Прелесть этого в том, что макрос делает именно то, что вы хотели бы получить от "template 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) { .... }