I have a template function as follows:

template <typename T>
int my_func(T& arg)

T is expected to be of type map<T1, T2>. T1 is expected to be of a basic type (int, long, etc.) and T2 is expected to be of type vector<T1>/list<T1>/etc.

I want to iterate over the contents of T2. How can I do this when I do not know what type T2 is? For example:

T2::const_iterator pos = ...;

Here's an example that does directly what you want:

template <typename T>
int my_func(T& arg) {
  int count = 0;
  typename T::iterator end = arg.end();
  for (typename T::iterator p = arg.begin(); p != end; ++p) {
    std::cout << "Key: " << p->first << "\n";
    typename T::mapped_type::iterator value_end = p->second.end();
    for (typename T::mapped_type::iterator q = p->second.begin(); q != value_end; ++q) {
      count = count + 1;
      std::cout << "  " << *q << "\n";
    }
  }
  return count;
}


int main() {
  std::map<std::string, std::vector<std::string> > m;
  std::vector<std::string> x, y;
  x.push_back("hello");
  x.push_back("good day");
  x.push_back("hey");
  y.push_back("what");
  y.push_back("okay");

  m.insert(std::pair<std::string, std::vector<std::string> >("x", x));
  m.insert(std::pair<std::string, std::vector<std::string> >("y", y));

  int n = my_func(m);
  std::cout << n << std::endl;
}

The thing is, I would prefer this design:

template <typename T, template <typename> class Container>
int my_func(std::map<T, Container<T> > arg) {
  typedef std::map<T, Container<T> > Map;
  typedef typename Map::iterator Iter;
  typedef typename Container<T>::iterator CIter;

  int count = 0;
  Iter end = arg.end();
  for (Iter p = arg.begin(); p != end; ++p) {
    std::cout << "Key: " << p->first << "\n";
    CIter value_end = p->second.end();
    for (CIter q = p->second.begin(); q != value_end; ++q) {
      count = count + 1;
      std::cout << "  " << *q << "\n";
    }
  }
  return count;
}

It more clearly describes what you're doing, since you know you're expecting a map<T, container<T> >.

Edited 3 Years Ago by mike_2000_17: Fixed formatting

Thanks, that is just what I was looking for.

What does this mean: template <typename> class Container ? I can figure out what it does, but typename is not followed by a name, which I find confusing. Also, in terms of templates, isn't class a synonym for typename ?

I guess you could write template <class> class Container . For whatever reason, template <typename> typename Container will not work. I guess it's because there's no such thing as a "template <typename> typename", but there is such a thing as a "template <typename> class". template <class> class Container says that Container is a templated class. That Container<T> would be the actual name of a type.

> typename is not followed by a name, which I find confusing
since the intent is to declare a template template type (ttp), the identifier following typename is just a place-holder (like the name of a formal parameter to a function) and can be omitted.
http://www.comeaucomputing.com/techtalk/templates/#ttp

a standard container has *two* template parameters; the value_type and the allocator_type.
the function should be:

template< typename T, typename A, template
          <typename VALUE_TYPE,typename ALLOCATOR_TYPE> class Container >
int my_func( std::map<T, Container<T,A> >& arg ) 
{
  typedef std::map< T, Container<T,A> > Map;
  typedef typename Map::iterator Iter;
  typedef typename Container<T,A>::iterator CIter;

  int count = 0;
  // ...
  return count;
}

No, that just makes things more complicated. If you're never going to use a custom allocator, it doesn't make any sense to do that extra work.

> If you're never going to use a custom allocator, it doesn't make any sense to do that extra work.
the fundamental problem with your code is not that it does not cater for a custom allocator for the container. it is that it does not compile.

> If you're never going to use a custom allocator, it doesn't make any sense to do that extra work.
the fundamental problem with your code is not that it does not cater for a custom allocator for the container. it is that it does not compile.

What compiler are you using?

What compiler are you using?

gcc 4.0.1

@vijayan121: Thanks for the info, I have updated my code.

----------

As a matter of style, is it better (in general) to write:

template <typename T1, 
          typename T2, 
          template <typename A, typename = std::allocator<A> > class CONT>
void create_paths(std::map<T1, CONT<T1> >& arg1, 
                  std::multimap<T2, T1>& arg2);

or

void create_paths(std::map<int, std::list<int> > arg1, 
                  std::multimap<char, int> arg2);

On the one hand, the former allows for a variety of types yet looks horrific and adds to compilation time, while the latter is simple and works.

Which would or do you use as an experienced C++ programmer?

Ignore the pass-by-value/pass-by-reference discrepancies in the function declarations in my previous post.

if it is to be part of a reusable library, as general as possible (perhaps with some syntactic sugar).
if not, just sufficient to meet the (future) requirements of the program i'm writing.

This question has already been answered. Start a new discussion instead.