Niranjan Kotha
Niranjan Kotha

Reputation: 309

What do member types mean in vectors?

When I went through std::vector over at cppreference.com and found a section called "Member types" I did not understand what that means. In fact the member types section is present in all the reference documents of containers in stl library.

Can someone help me in understanding this?

Upvotes: 6

Views: 855

Answers (4)

Karl Nicoll
Karl Nicoll

Reputation: 16419

The member types define the types that are used by the vector object. Many standard containers use member types to describe the types used, so that the programmer does not need to figure them out manually. This is particularly useful when working with complex templates, where types may be hard to determine.

For example, the return type of std::vector<___>::size() is usually std::size_t, however another C++ vector implementation may return a different integer type (e.g. int32_t). Instead of assuming what types you need in your code (and possibly introducing dangerous casting), you can simply use the member types exposed by the vector to write your code with the perfect types every time. For example:

std::vector<int> vec;

const std::vector<int>::value_type val = 4;
// std::vector<int>::value_type is a typedef of int!

vec.push_back(val);

const std::vector<int>::size_type size = vec.size();
// std::vector<int>::size_type is a typedef of std::size_t, usually.

const std::size_t size2 = vec.size();
// same as above, but we assume that vec.size() returns a size_t.
// If it does not, we may cause a narrowing conversion!

for (std::vector<int>::const_iterator it = vec.begin(), end = vec.end(); it != end; ++it)
{
    // The const_iterator type is also a member type of vector.
    std::cout << *it << std::endl;
}

Iterators are probably the most common usage of member types in standard containers. Rather than having to figure out if an iterator is a random access iterator, or a simple forward iterator, or any other kind of iterator, we can just use the iterator member type exposed by the container.

The C++11 auto keyword can take this even further. Instead of doing:

const std::vector<int>::size_type size = vec.size();

we can now just do:

const auto size = vec.size();

and the compiler will automatically work it out.

Generally speaking most C++ standard objects will use the same member types where possible (e.g. size_t for size_type, T for value_type, T& for reference_type), but it is not guaranteed (iterator member type is different for std::vector and std::list, because their implementations are wildly different and they cannot use the same iterator type).

Upvotes: 8

HolyBlackCat
HolyBlackCat

Reputation: 96256

There are two things you need to understand:

  1. You can make aliases for types.

For example,

using blah = int;

would make blah an alias for int. In other words, you would be able to use blah instead of int in any place.

(There is another way to make a type alias using typedef instead of using, but it is less readable.)

  1. You can put those aliases inside of classes.

For example, if you declared a following struct

struct S
{
    using type = int;
};

you would be able to use S::type instead of an int.

Such aliases inside of classes are often called member types.

Upvotes: 0

kfsone
kfsone

Reputation: 24249

The page you linked lists a "member type" of "value_type T". This is type definition that belongs to or is a member of T. Consider

using VEC = std::vector<double>;
VEC dv { 4.2 };

Now lets say we want to store a value from dv but we don't want to hard-code the type so that a future change to the definition of VEC will Do The Right Thing (TM).

using VEC = std::vector<double>;
VEC dv { 4.2 };
// ...    
VEC::value_type d = dv.front();

Or if you want to write cross-platform portable code, it can be helpful to use 'size_type' to ensure you store sizes that are large enough:

int s = dv.size();  // wrong on 64-bit system
VEC::size_type s = dv.size();  // always correct

That is to say, std::vector<double> hosts a type definition, value_type, which evaluates to the type of 'T' in vector, or in our case double.

This is mostly important for generic programming:

template<typename T>
void dothing(const T& container)
{
    T::const_pointer* c = &container;  // for some reason I need it's address
    // .. other stuff
}

Upvotes: 1

Kerrek SB
Kerrek SB

Reputation: 477040

Here's a typical class in C++:

struct Foo
{
    int n;                         // non-static data member
    static const float x;          // static data member

    int f() const;                 // non-static member function
    static int g();                // static member function

    template <typename T>
    void h(T);                     // non-static member function template

    struct X { bool a; };          // member type
    template <typename> struct Q;  // member class template

    using T = Q<int>;              // member type (member typedef)
};

Example usage:

// Use static members

print(Foo::x);
print(Foo::g());

Foo::X y;
Foo::Q<double> z;
Foo::T w;

// Use non-static members (requires instance)

void demo(const Foo & a)
{
    print(a.n);
    print(a.f());
    print(a.h<float>());
}

Upvotes: 3

Related Questions