18

how can i get the type of the elements that are held by a STL container?

Patrick Oscity
  • 53,604
  • 17
  • 144
  • 168
  • 1
    Exactly what are you trying to do here? Since C++ is statically typed, you should generally know what type the elements are (vector, for example, holds ints). If you'd explain why you don't know what the types are, and what you want to use them for, that would help answer the question. – David Thornley Nov 10 '09 at 16:11
  • @David Thornley: `template void foo(std::template arg){ /* Here, we don't know what the elements type is */ }` I think it's a pretty common situation. – jalf Nov 10 '09 at 16:42
  • @Jalf: At that point true. But at that point foo() is only a concept. But as soon as you use foo() you also know the type. – Martin York Nov 10 '09 at 18:35

8 Answers8

22
container::value_type
KeatsPeeks
  • 19,126
  • 5
  • 52
  • 83
  • ok that's already great, but i can't seem compare two value types returned by container::value_type. any suggestions? – Patrick Oscity Nov 10 '09 at 16:02
  • 2
    @Patrick: you can't compare the "values returned by value_type" because value_type is a type, not a value. Comparing two value_types is thus a static operation, not a runtime one. Depending on what you are trying to achieve, you may want to look at "is_same" in Boost.TypeTraits: http://www.boost.org/doc/libs/1_40_0/libs/type_traits/doc/html/boost_typetraits/reference/is_same.html – Éric Malenfant Nov 10 '09 at 16:16
  • 2
    @Patrick: You asked for the *type* of elements stored in the vector, not the *value* of the elements. You can compare the values, you can't compare types (at least not without a lot of metaprogramming tricks) - perhaps you should explain what it is you're trying to do. – jalf Nov 10 '09 at 16:43
  • Maybe need to add typename? – Kargath Apr 26 '22 at 11:15
20

For containers in general it will be X::value_type. For associative containers it will be X::mapped_type (X::value_type corresponds to pair<const Key,T>). It is according to Chapter 23 of C++ Standard.

To check that types are equal you could use boost::is_same. And since C++11 — std::is_same.

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
  • 2
    Update: we now have [`std::is_same`](https://en.cppreference.com/w/cpp/types/is_same). – kebs Jul 13 '21 at 17:55
5

Checking whether two types are the same can be achieved like this (without RTTI, value is usable at compile-time):

template <class T, class U>
struct same_type
{
    static const bool value = false;
};

//specialization for types that are the same
template <class T>
struct same_type<T, T>
{
    static const bool value = true;
};

//sample usage:
template <class FirstContainer, class SecondContainer>
bool containers_of_same_type(const FirstContainer&, const SecondContainer&)
{
    return same_type<
        typename FirstContainer::value_type, 
        typename SecondContainer::value_type
    >::value;
}

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

int main()
{
    std::cout << containers_of_same_type(std::vector<int>(), std::list<int>());
    std::cout << containers_of_same_type(std::vector<char>(), std::list<int>());
}

(This is basically how boost::is_same works, minus workarounds for certain compilers.)

UncleBens
  • 40,819
  • 6
  • 57
  • 90
0

In what sense? Maybe using RTTI and typeid()?

Probably you have to use container::valuetype where container is the name of your container (for example std::vector)

Alek

0

You need to give us more context. If you mean you want the value known at compiletime so it's easy to change it then use container::value_type.

typedef vector<int> coordinates;

coordinates seq;
fib::value_type elem = seq.back(); // it's easy to change int type

If what you mean is that the container may hold various concrete (derived) types and you wish to know them at runtime then you should probably re-evaluate your approach. In object-oriented programming hiding the type at runtime is sometimes a powerful approach, because it means you make fewer assumptions about what you're working with. You can of course use RTTI, but there's probably a better way: we'd need more context to tell.

If you wish to compare types then you're probably heading the runtime path. C++ supports polymorphism, which is essentially that type-comparison you're looking after -- but built into the language. You want to execute a different set of instructions based on the type? Polymorphism allows you to execute a different function based on the type of the object. You need not write a single extra line of code -- only derive from a common base.

wilhelmtell
  • 57,473
  • 20
  • 96
  • 131
0

Use something like this:

if (typeid(yourVariable)==typeid(YourClass)) //...

Alek

0

given the types are known statically you can check they are the same statically without using rtti by using template specialization. e.g. use something like http://www.boost.org/doc/libs/1_40_0/libs/type_traits/doc/html/boost_typetraits/reference/is_same.html or if boost isn't available roll your own

jk.
  • 13,817
  • 5
  • 37
  • 50
0

A user defined container type - call it ContainerType - that supports ContainerType::begin (), and ContainerType::end () methods could use, in C++ 20,

using DataType = std::ranges::range_value_t<ContainerType>;

to reference the type of data if needed. Here's an example

#include <iostream>
#include <array>
#include <vector>
#include <ranges>

template <typename T, size_t N>
struct MyContainer
{   
    T * begin () { return m_Arr.data (); }
   
    T * end () { return m_Arr.data () + m_Arr.size (); }
   
    std::array<T, N> m_Arr;
};

template <typename ContainerType> std::vector<std::ranges::range_value_t<ContainerType>> ToVector (ContainerType cc)
{
    using DataType = std::ranges::range_value_t<ContainerType>;
    std::vector<DataType> res;
    for (const auto &value: cc)
    {
        res.push_back (value);
    }
    
    return res;
}


int main ()
{
    MyContainer<double, 4> cc{{0.5, 1., 2., 3.}};
    const auto myVector = ToVector (cc);
    
    for (auto vv: myVector)
        std::cout << vv << "\n";
    
    return 0;
}
Catriel
  • 461
  • 3
  • 11