开发者

An std container inside a template method

开发者 https://www.devze.com 2023-02-14 05:57 出处:网络
Greetings. I don\'t know very well how to explain myself, but I believe a piece of code will make you understand what I\'m intenting to do :

Greetings.

I don't know very well how to explain myself, but I believe a piece of code will make you understand what I'm intenting to do :

template<class A, class B>
void myFunction(A<B>& list)
{
  typename A<B>::iterator current = list.begin();
  typename A<B>::iterator end = list.end();

  while (current != end)
  {
    current++;
  }
}

Where A is an STL container (vector, list...). It's like inception, but with templates : a template, inside a template, etc...

The thing is : what do you do when one of the params of your template is itself a template... and still want开发者_运维问答 to support every types supported by this template.

This of course doesn't compile (it says 'A is not a template').

Does someone knows how to create such a template ?


You are looking for a template template parameter

template<template<class T, class All = std::allocator<T> > class A, class B>
void myFunction(A<B>& list)
{
  typename A<B>::iterator current = list.begin();
  typename A<B>::iterator end = list.end();

  while (current != end)
  {
    current++;
  }
}

However, in your particular case, I think you'd be better off by just passing the intantiated container, that is,

template<class C>
void myFunction(C& list)
{
   ...
}

use like this

vector<char> v;
myFunction(v);

Your original code would have to be called like this:

myFunction<std::vector, char> (v)

which is much more verbose and has no particular benefit


A and B will be concrete types (and not templates), thus A<B> makes no sense.

You can write your code this way:

template<class List>
void myFunction(List &list)
{
  typename List::iterator current = list.begin();
  typename List::iterator end = list.end();

  while (current != end)
  {
    current++;
  }
}

If you need to know what is the type of an element of that list, there is a typedef inside of the list for that:

typename List::value_type


Well, to solve this little example problem. It's quite simple. vector<int> is a class, so, you don't need to declare the A<B> in the prototype. You can just do this:

template<class A>
void myFunction(A& list)
{
  typedef typename A::value_type B; //do this if you need to know the type of the elements.
  typename A::iterator current = list.begin();
  typename A::iterator end = list.end();

  while (current != end)
  {
    current++;
  }
}

But if you really need to, you can also declare the template argument as a template too:

template< template<class> class A, class B >
void myFunction(A<B>& list)
{
  typename A<B>::iterator current = list.begin();
  typename A<B>::iterator end = list.end();

  while (current != end)
  {
    current++;
  }
}

But the above is not really recommended and most class templates have a set of nested typedefs (like iterator and value_type in STL containers) so that you can access have all the information you need about the type without having to use these template template parameters. So, the first way is usually the preferred and more normal way to do it (it also is usually less trouble to make it work, i.e., the compiler tends to "dislike" template template parameters).

Additionally, you cannot use STL containers very easily with template template parameters because STL containers all have these "hidden" template arguments (e.g. "allocator", and "compare" for sorted containers). So, you would have to list all these as well, otherwise the compiler will not be able to make the match. And then, you won't have a very "generic" function because you will have to assume so much about the STL container that is past that it will only serve one or two types of containers. It is really better to use the first way.

0

精彩评论

暂无评论...
验证码 换一张
取 消