Функция шаблона принимает любой тип, похожий на карту - PullRequest
2 голосов
/ 07 ноября 2011

Есть ли способ заставить что-то вроде этого работать:

template<typename T, typename X, typename Y>
void myFunc(T<X,Y> map, X x, Y y) {
    map[x] += y;
}

В основном я хочу, чтобы все, что действует как map<X,Y>, было допустимым вводом.

Возможно ли это?

Я получаю эту ошибку, но я не знаю, что это значит:

test.cpp: 2: 17: ошибка: 'T' не шаблон

Ответы [ 3 ]

4 голосов
/ 07 ноября 2011

Да, с аргументами шаблона шаблона:

template <template <typename, typename> class M, typename K, typename V>
void Foo(M<K, V> & container)
{
  // ...
};

Обратите внимание, что это никогда не будет соответствовать ни одному контейнеру реального слова, потому что у них гораздо больше аргументов шаблона.Лучше с variadics:

template <template <typename, typename, typename...> class M, typename K, typename V, typename ...Args>
void Foo(M<K, V, Args...> & container)
{
  // ...
};

Если variadics не вариант, вы можете использовать немного обертывания самостоятельно:

template <typename Container> void FooImpl(Container &);

template <template <typename, typename> class M,
          typename K, typename V>
void Foo(M<K,V> & c) { FooImpl(c); }

template <template <typename, typename, typename> class M,
          typename K, typename V, typename A1>
void Foo(M<K,V,A1> & c) { FooImpl(c); }

template <template <typename, typename, typename, typename> class M,
          typename K, typename V, typename A1, typename A2>
void Foo(M<K,V,A1,A2> & c) { FooImpl(c); }

// etc.

Для справки std::unordered_map принимает пять параметров шаблонаключ, значение, хеш-функтор, предикат равенства, распределитель).Boost bimap может потребовать еще больше.

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

3 голосов
/ 07 ноября 2011

Самый простой способ - использовать просто T в качестве типа аргумента.

template<typename T, typename X, typename Y>
void myFunc(T map, X x, Y y) {
    map[x] += y;
}

Обратите внимание, что это позволит, например. массивы как T с (например, T = int*, X = int, Y = int, и функция добавит y к x -ому элементу массива map.

Если вы хотите сузить его до карт, вы должны решить, что является картой в соответствии с вами. Одной из возможностей распознавания карт будет проверка их key_type и mapped_type. Eg.:

template<typename T>
void myFunc(T map, typename T::key_type x, typename T::mapped_type y) {

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

1 голос
/ 07 ноября 2011

Если вы не ограничите тип карты T, все станет намного проще:

template<typename T, typename X, typename Y>
void myFunc(T map, X x, Y y) {
    map[x] += y;
}

// ...

map<int, int> myMap;
myFunc(myMap, 5, 7);

std :: map на самом деле имеет больше параметров, чем просто K и V (у него также есть компаратор и распределитель), поэтому, вероятно, лучше не сопоставлять его аргументы шаблона. Приведенный выше код будет по-прежнему компилироваться только для тех объектов, у которых есть неконстантный оператор [], принимающий X в качестве ключа и возвращающий Y в качестве значения, но он также гибок для контейнеров, которые не являются конкретно Container, например, Container .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...