2

Is there any way to make something like this work:

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

Basically I want anything that acts like a map<X,Y> to be valid input.

Is this possible?

I get this error but I don't know what it means:

test.cpp:2:17: error: ‘T’ is not a template

Brendan Long
  • 53,280
  • 21
  • 146
  • 188
  • Why not just `template void myFunc(std::map map) { ... }` ? – Oliver Charlesworth Nov 07 '11 at 00:43
  • @Oli Charlesworth - Because I want my function to accept `map`, `unordered_map`, `concurrent_hash_map`, etc. – Brendan Long Nov 07 '11 at 00:46
  • Perhaps a slightly more semantic approach than my overly broad answer would be to check for the existence of a `key_type` and `mapped_type` member type. That could be done with trait checks. On the other hand, the square-bracket operator is really very special and only exists for very few data structures... – Kerrek SB Nov 07 '11 at 01:05
  • Aside: you probably want `map` to be passed by reference – Caleth Aug 10 '20 at 12:48

3 Answers3

5

Yes, with template template template arguments:

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

Note that this will never match any real-word container, though, because those have many more template arguments. Better with variadics:

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

If variadics aren't an option, you could leverage a bit of wrapping yourself:

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.

For reference, std::unordered_map takes five template parameters (key, value, hash functor, equality predicate, allocator). Boost's bimap might take even more.

Abuse of this last construction could be prevented by making the functions static members of a wrapper class and making the implementation private, and by providing a single free accessor helper function.

relaxxx
  • 7,566
  • 8
  • 37
  • 64
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
4

The simplest way is to use just T as argument type.

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

Note that this will allow eg. arrays as Ts (eg. T = int*, X = int, Y = int and the function will add y to the x-th element of array map.

If you want to narrow it down to maps, you have to decide what is a map according to you. One possibility of recognizing maps would be inspecting for their key_type and mapped_type. Eg.:

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

If you really want accept anything that takes two type arguments (and not more), you can use template-template arguments. I, however, think that this is an overly syntactic distinction, and you shouldn't use it unless you plan to instantiate the template-template parameter with multiple argument types.

jpalecek
  • 47,058
  • 7
  • 102
  • 144
1

If you don't constrain map to be of type T, things become much simpler:

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 actually has more parameters than just K and V (it has a comparator and an allocator as well), so it's probably better to not match it's template arguments. The code above will still only compile for things that have a non-const operator[] taking an X as a key and returning a Y as a value, but it is also flexible for containers that aren't specifically Container, for example, Container.

Aria Buckles
  • 923
  • 5
  • 10