Можете ли вы использовать шаблоны C ++ для указания типа коллекции и специализации этого типа? - PullRequest
4 голосов
/ 05 июня 2009

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

template <class CollectionType, class ItemType>
class Test
{
public:
    CollectionType<ItemType> m_collection;
};

Так что я могу сделать:

Test  t = Test<vector, int>();
t.m_collection<vector<int>> = vector<int>();

Но это порождает

test.cpp:12: error: `CollectionType' is not a template

Ответы [ 3 ]

14 голосов
/ 05 июня 2009

То, что вы хотите, это параметр шаблона шаблона:

template <template <typename> class CollectionType, class ItemType>
class Test
{
public:
    CollectionType<ItemType> m_collection;
};

Здесь мы указали, что первый параметр шаблона, т.е. CollectionType, является шаблоном типа. Следовательно, Test может быть создан только с типом, который сам является шаблоном.

Однако, как указал @Binary Worrier в комментариях, это не будет работать с контейнерами STL, поскольку они имеют 2 шаблонных параметров: один для типа элементов, другой для типа распределителя используется для управления распределением памяти (значение по умолчанию).

Следовательно, вам нужно изменить первый параметр шаблона, чтобы он имел два параметра:

template <template <typename,typename> class CollectionType, class ItemType>
class Test
{
public:
    CollectionType<ItemType> m_collection;
};

Но подождите, это тоже не сработает! Действительно, CollectionType ожидает другого параметра, распределителя ... Итак, теперь у вас есть два решения:

1. Принудительно использовать определенный распределитель:

CollectionType<ItemType, std::allocator<ItemType> > m_collection

2. Добавьте параметр шаблона для распределителя в ваш класс:

template <template <typename,typename> class CollectionType, 
          class ItemType,
          class Allocator = std::allocator<ItemType> >
class Test
{
public:
    CollectionType<ItemType, Allocator> m_collection;
};

Итак, как вы видите, в итоге вы столкнулись с чем-то довольно сложным, которое, кажется, действительно искажено для работы с контейнерами STL ...

Мой совет: см. Ответ Грега Роджерса для лучшего подхода:)!

10 голосов
/ 05 июня 2009

Почему бы не сделать это так?

template <class CollectionType>
class Test
{
public:
    CollectionType m_collection;
};

Test  t = Test<vector<int> >();
t.m_collection = vector<int>();

Если вам нужен тип предмета, вы можете использовать CollectionType::value_type.

РЕДАКТИРОВАТЬ: в ответ на ваш вопрос о создании функции-члена, возвращающей тип_значения, вы делаете это так:

typename CollectionType::value_type foo();

Вы добавляете typename, потому что CollectionType еще не привязан к фактическому типу. Так что нет значения типа, который он мог бы искать.

2 голосов
/ 05 июня 2009

Comeau онлайн нравится это:

#include <vector>

template <template <class T, class A = std::allocator<T> > class CollectionType, class ItemType>
class Test
{
public:
    CollectionType<ItemType> m_collection;
};

void foo()
{
using std::vector;
Test<vector,int>  t = Test<vector, int>();
t.m_collection = vector<int>();
}
...