Создание шаблона класса контейнера - PullRequest
3 голосов
/ 27 марта 2019

Я пытаюсь создать класс как контейнер-оболочку, что-то вроде этого

#include <vector>

template <typename T, typename U>
class Test {
    T<U> list;
};

int main() {
  Test<std::vector, int> test;
}

Но это не сработает.Я знаю, что это будет работать, когда я использую это как

#include <vector>

template <typename T>
class Test {
    T list;
};

int main() {
  Test<std::vector<int>> test;
}

, но как мне написать мою вставку?

template <typename T>
class Test {
    T list;

public:
    void insert(??? element) {
        ...
    }
};

TIA, Narase

Ответы [ 2 ]

3 голосов
/ 31 марта 2019

Самый простой будет

template <typename T>
class Test {
    ....
    void insert(const typename T::value_type& element);

И / или, для полноты и соответствия семантики перемещения:

void insert(typename T::value_type&& element);
3 голосов
/ 31 марта 2019

Но это не сработает.

С вашим первым фрагментом Test, поскольку std::vector имеет два параметра шаблона, value_type и allocator_type, мы должны указать наличие этих параметров шаблона в объявлении T используя параметры шаблона шаблона следующим образом. Здесь я использую переменную, и тогда T<U...> становится законным для T = std::vector и ошибки компиляции устранены.

как мне написать мою вставку?

Следующий код также показывает пример реализации Test::insert. Поскольку этот метод может принимать ссылки как lvalue, так и rvalue в C ++ 11 и более поздних версиях, здесь я применяю ссылку пересылки (то, что Скотт Мейерс называет универсальным ссылка ,) на него. При таком подходе нам не нужно указывать тип значения Test::list в определении Test::insert, а передача неправильных типов в Test::insert вызывает ошибки компиляции. Если вам нужен тип значения std::vector, доступен тип элемента std::vector::value_type:

template <template<class...> class T, class ...U>
class Test
{
    T<U...> list;

public:
    template<class ...V>
    void insert(V&& ...element) {
        list.insert(std::forward<V>(element)...);
    }

    typename T<U...>::iterator begin() noexcept {
        return list.begin();
    }

    typename T<U...>::iterator end() noexcept {
        return list.end();
    }

    using value_type = typename T<U...>::value_type;
};

Это пример использования с std::vector:

DEMO (std :: vector)

static_assert(
    std::is_same<Test<std::vector, int>::value_type, int>::value, "oops!"); // OK.

Test<std::vector, int> test; // OK

test.insert(test.end(), 11);
test.insert(test.end(), 99);

for(auto it = test.begin(); it != test.end(); ++it){
    std::cout << *it << std::endl;
}

В качестве другого примера этот класс-оболочка также работает с std::map следующим образом:

ДЕМО (std :: map)

static_assert(
    std::is_same<Test<std::map, int, int>::value_type, std::pair<const int, int>>::value, "oops!"); // OK.

Test<std::map, int, int> test; // OK

test.insert(std::make_pair(1, 11));
test.insert(std::make_pair(2, 99));

for(auto it = test.begin(); it!= test.end(); ++it){
    std::cout << it->first << ", " << it->second << std::endl;
}

Наконец, это исправленная версия вашего второго фрагмента:

DEMO (std :: vector)

DEMO (std :: set)

template <class T>
class Test
{
    T list;

public:
    template<class ...V>
    void insert(V&& ...element) {
        list.insert(std::forward<V>(element)...);
    }

    typename T::iterator begin() noexcept {
        return list.begin();
    }

    typename T::iterator end() noexcept {
        return list.end();
    }

    using value_type = typename T::value_type;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...