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 = ...;

Recommended Answers

All 13 Replies

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> >.

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.

sarehu's code works for me.

> 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.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.