C++ Get Vector type

24,076

Solution 1

There are two ways to accomplish this.

1) Either you make use of the fact that std::vector<> (like all standard library container classes) maintains a member type value_type, which represents the type of the elements stored in the vector. So you can do this:

template <typename T> void SomeFunc() {
  typename T::value_type s;  // <--- declares a `std::string` object
                             //      if `T` is a `std::vector<std::string>`
}

2) Or else, you change the declaration of your function and make use of template template parameters:

template <template <typename> class T, typename Elem>
void SomeFunc(T<Elem> &arg)
{
  Elem s;
}

However, there is a small problem with that: std::vector is really a template with two parameters (element type and allocator type), which makes it a little difficult to use the template template parameters and still keep the syntax simple. One thing that worked for me is to declare an alias of the vector type that leaves only one template parameter:

template <typename Elem>
using myvector = std::vector<Elem>;

Then I can use SomeFunc like this:

int main()
{
  myvec<std::string> vec;
  SomeFunc(vec);
}

Solution 2

In c++11, you can use decltype and std::decay to that effect:

std::vector<int> vec; using T = typename std::decay<decltype(*vec.begin())>::type;

Share:
24,076
kyall
Author by

kyall

I'm sort of convinced there's a spam bot out there that exists purely to answer people's programming questions with boost utils that don't actually apply to the programmer's query except by something like google search: Templated Callback site:boost doco

Updated on December 13, 2020

Comments

  • kyall
    kyall over 3 years

    I'm using template functions for object construction to create objects from reflection data, and it works pretty well, but now I want to support STL container types in the reflection system so that objects such as:

    // Note - test case only
    // for real world usage it would probably not be structured like this 
    // and the phrases would be mapped by an id or something 
    struct Phrases {
      std::vector<std::string> phrases;
    };
    
    typedef std::string Lang;
    struct Langs {
      std::map< Lang, Phrases > translations;
    };
    

    Can be supported. I can do some regex magic on the return of

    typeid( object ).name() 
    

    to figure out if an object is a vector or a map, and what the parameter arguments for the object is. And I have tried some template magic to do it something like the following, where CreateString, ConstructString & DestroyString are stand in functions and the data is stand in as well for something a bit more complex that uses a type database to handle object construction.

    // Representational of code, basically a copy-paste to a different test project where I can work out the problems with this specific vector problem 
    // Vector specialised construction 
    template <typename T> void ConstructVector( void* object, const std::vector<std::string>& data ) {
      T* vec = (T*)object;
      Name vector_type = GetVectorTypeName<T>();
    
      void *obj; 
      CreateString(&obj);
      // All fields in this type should be valid objects for this vector 
      for( std::vector<std::string>::const_iterator it = data.begin(), end = data.end(); it != end; ++it ) {
        // Push it 
        vec->push_back(*obj);
        // Get address to new instance 
        void *newly = &vec->back(); 
        ConstructString(newly,*it);
      }
      DestroyString(&obj);
    
    }
    

    Which doesn't work owing to the illegal indirection with "vec->push_back(*obj);" which I can't case because I don't actually know the type. Basically what I need to be able to do is create this vector with some blank unset elements already in it, or add new elements to it without actually having the type, because if I can get a pointer to a memory block inside the vector I can roll with that and construct the object. But the vector add requirements such as

    vector::push_back( T& value ) 
    

    or

    vector::insert( Iter&, T& ) 
    

    Won't work for me unless I can get my hands on that T type from inside the template

    pastebin of testing code to try and solve this: http://pastebin.com/1ZAw1VXg

    So my question is, how can I get the std::string part of a std::vector declaration when I'm inside a template like

    template <typename T> void SomeFunc() {
    
      // Need to get std::string here somehow       
      // Alternatively need to make the vector a certain size and then 
      // get pointers to it's members so I can construct them 
    }
    
    
    SomeFunc<std::vector<std::string>>>();