How can I get sizeof a vector::value_type?
Asked Answered
P

4

32

I want to get sizeof of the type that is contained in a vector. Here is what I tried:

#include <iostream>
#include <vector>

int main()
{
    std::vector<uint> vecs;
    std::cout << sizeof(vecs.value_type) << std::endl;
    return 0;
}

From my understanding this should be correct. However, when compiling with GCC 4.8.1 this is what I get:

test-sizeof.cpp: In function ‘int main()’:
test-sizeof.cpp:7:27: error: invalid use of ‘std::vector<unsigned int>::value_type’
  std::cout << sizeof(vecs.value_type) << std::endl;
                           ^

What am I doing wrong? How can I get the size of the contained type?

Phototelegraph answered 22/1, 2014 at 18:21 Comment(6)
Use std::vector<uint>::value_typeSuh
sizeof(std::vector<uint>::value_type) or sizeof(decltype(vecs)::value_type).Uigur
Thanks, the decltype trick is what I used. If you can find the time can you please post a detailed explanation what is going on here? I think I have a vague idea but not enough that I might explain it in detail.Phototelegraph
Why not simply sizeof(vecs[0])?Bein
@HagenvonEitzen Would that work even if the vector has zero elements?Phototelegraph
Yes, because the operand is not evaluated. (Yeah I'm late. :|)Cavendish
M
22

3.4.3 Qualified name lookup [basic.lookup.qual]

1 The name of a class or namespace member or enumerator can be referred to after the :: scope resolution operator (5.1) applied to a nested-name-specifier that denotes its class, namespace, or enumeration. If a :: scope resolution operator in a nested-name-specifier is not preceded by a decltype-specifier, lookup of the name preceding that :: considers only namespaces, types, and templates whose specializations are types. If the name found does not designate a namespace or a class, enumeration, or dependent type, the program is ill-formed.

In this case, you are accessing a type member from the class template specialization std::vector<uint>, and you need to do it by writing:

std::vector<uint>::value_type

In case you are actually inside templated code and want to e.g. access the same nested type, you need to prefix it with the keyword typename like this:

typename std::vector<T>::value_type

In C++11, you can use sizeof(decltype(vecs)::value_type) or also sizeof(decltype(vecs.back())), the latter is convenient if you don't know the precise name of the type but know how to access them through a member function like back().

Note: as pointed out by @Casey in the comments, decltype requires stripping references in order to get the type itself, but for sizeof purposes that doesn't matter.

Miscount answered 22/1, 2014 at 18:37 Comment(7)
Re. the last paragraph, both . and -> can be used to access static data members or functions, which are class members. It just cannot be used to access a type.Thornhill
@DavidRodríguez-dribeas tnx, I removed that section as I don't want to go into all that detail about ..Miscount
...and enumerators! Let us not neglect the poor defenseless enumerators.Uigur
Nit: decltype(vecs.back()) is decltype(vecs)::value_type& and requires stripping with std::remove_reference or std::decay to get to the pure type.Uigur
@Uigur tnx, but for sizeof() purposes, that isn't necessary. Updated though.Miscount
Note that decltype(vecs)::value_type won't work if vecs is a std::vector<T>&. It's necessary to use the even more cumbersome std::remove_reference_t<decltype(vecs)>::value_type.Earwitness
Since sizeof() can be passed an expression, not just a type, it's not necessary to use decltype() to turn an expression into its type. E.g., sizeof('x') is valid as is, there is no need to write sizeof(decltype('x')). This leads to what I think is the best answer to the original question. Get the size using sizeof(vecs[0]). It's perfectly safe to use std::vector::operator[] in this unevaluated context. It's very concise and it works for vectors, other containers, and even C arrays or pointers. E.g., in a template where the type of vecs could be many things besides vector.Earwitness
R
14

The member access operator . can only be used to access data members and member functions of classes, not other nested names such as type names. You'll need the scope resolution operator :: to access them, and that can only be applied to the class name (or an alias), not an object of class type:

std::vector<uint>::value_type

In C++11 or later, decltype can give you a type name, if you have an object and no convenient access to the type:

decltype(vecs)::value_type
Radloff answered 22/1, 2014 at 18:34 Comment(2)
Nitpick nazi says: Nested types are members of classes §9.2/1 "Members of a class are data members, member functions (9.3), nested types, and enumerators", but they are specifically excluded from member access expressions §5.2.5/4 "If E2 is a nested type, the expression E1.E2 is ill-formed."Uigur
@Casey: Thanks, I wasn't sure of the precise definition of "member". The answer is more correct now.Radloff
D
8

I prefer the more concise:

sizeof(vecs[0])

Which at first glance seems unsafe because what happens when vecs is a zero length vector?

For this example where the argument to sizeof() operator is called on a value type, the sizeof() operator is executed at compile time and so vecs[0] can never cause a segfault or crash.

p.s. sizeof() is only evaluated at runtime when the argument is a variable-length-array (from C or GNU C++ extension)

Darton answered 5/7, 2018 at 19:31 Comment(0)
A
3

The comments pretty much said it all: if you know the type of the vector, you can use sizeof(std::vector<uint>::value_type). Otherwise use sizeof(decltype(vecs)::value_type).

decltype is a magical C++11 construct that evaluates to the type of its argument, so the code

int i;
float f;

decltype(i) j;
decltype(f) g;

Is the same as

int i;
float f;

int j;
float g;

Only use the . operator for fields and methods (technically it can be used for static variable as well, but it's considered bad practice). For anything else, such as static variables, inner classes, or class-scope template parameters or typedefs (such as value_type), use the scope-resolution operator ::.

Avaunt answered 22/1, 2014 at 18:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.