шаблонный typedef? - PullRequest
       22

шаблонный typedef?

37 голосов
/ 16 марта 2009

Я использую 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> > >

EDIT: после попытки использования макроса я обнаружил, что следующий код ломает его:

#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 ]

68 голосов
/ 06 июня 2014

Вы можете использовать шаблонное псевдонимы C ++ 11, используя using, например. как это

template <typename T>
using gc_vector = std::vector<T, gc_allocator<T>>;

Примечание: я знаю, что это старый вопрос, но поскольку у него довольно много голосов, и, как оказалось, в результатах поиска я подумал, что он заслуживает обновленного ответа.

33 голосов
/ 16 марта 2009

Вы не можете использовать "шаблонный 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> >

EDIT - @chmike: Обратите внимание, что решение TypeHelper не не требует переопределения конструкторов!

8 голосов
/ 16 марта 2009

Вы можете публично наследовать:

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 ++, если вы когда-либо попытаетесь удалить переменную производного класса через указатель на переменную базового класса.

В реальном мире это не должно иметь значения в данном конкретном случае - производный класс не имеет ничего нового по сравнению с базовым классом, и поэтому деструктор для производного класса просто вызывает деструктор для базового класса. Продолжайте с паранойей, все равно осторожно переносите.

Если вы никогда не размещаете переменные этого класса в куче (а типичные переменные вектора выделяются в стеке и в качестве членов других классов), проблема не виртуального деструктора не влияет на вас.

1 голос
/ 31 января 2012

Это можно сделать с помощью MACRO, если вы хотите расширить свой компилятор до предела. Я сделал это во время реализации эквивалентов C ++ для классов Java "Future" и "Callable". Наша библиотека использует объекты с подсчетом ссылок, поэтому «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) { .... }
...