Question

I am trying to write a function which can take any of the standard containers(list, stack, vector etc) as it's arguments. I also wish to know the type that is within the container. Here is what I have tried.

#include<iostream>
#include<list>
#include<vector>

template<class data_type, template<class> class container_type>
void type(container_type<data_type>& _container){
        std::cout<<typeid(container_type).name()<<std::endl;
}


int main(){

    std::list<int> list_t;
    std::vector<int> vector_t;
    type(list_t);
    type(vector_t);
}

The type of container_type once inside this function is always _Container_base_aux_alloc_empty which(I think) is a base class of the standard containers.

What is going on here?

How would I make this function return the correct type?

Was it helpful?

Solution

Your code won't work, because as soon as someone swaps out the allocator or something like that, then you're done for. You should take any T and use ::value_type, if in C++03, or type deduction in C++0x.

Also, .name() isn't defined to return anything useful, at all. In any situation. An implementation could return "har har sucker! good luck using this language feature" for every type and be conforming.

OTHER TIPS

The typeid of container_type is no use, because that's just a template class, and a template class isn't a real type at all, it only becomes one after instantiation. So what you really want is the type of data_type for the value type, and the type of container_type<data_type> for the type of the instantiated container. Even better, of course, is to take container_type<data_type>::value_type as the value type.

Note that most containers take more than one template parameter, so you'd be better off writing this with variadic templates:

template <template <typename...> class Container, typename ...Args>
void print_type(const Container<Args...> &)
{
  typedef typename Container<Args...>::value_type value_type;
  print(typeid(Container<Args...>).name());
  print(typeid(value_type).name());
}

I would not trust the output of typeid() that much. type_info::Name is not guaranteed to return some unique identfier. So it might very well be the type inside the function is what you expect.

The best way to get some kind of name for the type is to use a macro, something like this:

template<class data_type, template<class> class container_type>
void type_helper(container_type<data_type>& _container, const char* charStr){
        std::cout<< charStr << std::endl
}

#define type(container) type_helper(container, #container)

You already have the type of the container. It's data_type. Just use it like this. If in doubt you can also use typename container_type::value_type which is a typedef for the template argument of the container.

So much for using types. Returning a type is something entirely different in C++ and is generally considered a part of template meta-programming.

This, rather pointless snippet, extracts the value_type from some type T.

template<typename T>
struct inner_type {
  typedef T::value_type value_type;
};

But you might as well use the value_type directly and avoid this piece of obfuscation.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top