Вопрос

Я использую 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) { .... }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top