Шаблонный 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" сам по себе является шаблоном класса, где "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>>

Прелесть этого в том, что макрос делает именно то, что вы хотите от "шаблона 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) { .... }
Другие вопросы по тегам