60

Given this struct:

struct Foo {
  std::array<int, 8> bar;
};

How can I get the number of elements of the bar array if I don't have an instance of Foo?

18
  • 2
    how about using a macro instead of hardcoding the array size? Commented Dec 27, 2016 at 12:27
  • 20
    @WebertS.Lima - Perish the thought. Not a macro. Commented Dec 27, 2016 at 12:31
  • 12
    @WebertS.Lima - std::array doesn't shrink or grow. It will always be 8 constructed objects. Commented Dec 27, 2016 at 12:39
  • 5
    @WebertS.Lima - No; if you declare a std::array<int, 8> you ever have a container with 8 elements; you can set the value of 4 of this elements (after the initialization) but the other 4 are present with initial value Commented Dec 27, 2016 at 12:47
  • 3
    Also, the array doesn't exist yet, I sure hope it's not half-full. Commented Dec 28, 2016 at 3:26

6 Answers 6

94

You may use std::tuple_size:

std::tuple_size<decltype(Foo::bar)>::value
Sign up to request clarification or add additional context in comments.

2 Comments

Hooking this here: the various classes and functions dealing with std::tuples (std::tuple_size, std::tuple_element, std::get) have handy specializations to treat an std::array<T, N> like a std::tuple<T, T, ..., T>.
Can be simplified in C++17 to std::tuple_size_v<decltype(Foo::bar)>
31

Despite the good answer of @Jarod42, here is another possible solution based on decltype that doesn't use tuple_size.
It follows a minimal, working example that works in C++11:

#include<array>

struct Foo {
    std::array<int, 8> bar;
};

int main() {
    constexpr std::size_t N = decltype(Foo::bar){}.size();
    static_assert(N == 8, "!");
}

std::array already has a constexpr member function named size that returns the value you are looking for.

5 Comments

so this has the same issue as @waxrat's answer below, it requires construction even if that construction may be constexpr, in that sense std::tuple_size is a better answer because it doesn't require any construction or destruction in the non-constexpr case.
@Mgetz I didn't say it's better. :-) ... Different solutions and answers can help future readers, no matter if they are the accepted ones or not.
hence my comment, I sought to ensure such readers would understand why std::tuple_size is a better choice. That said I'd probably do a using array_size = std::tuple_size for readability.
@Mgetz Names aren't the strongest feature of the language, I agree. We are dealing with a language that contains a function named std::move that doesn't move anything. What else? :-) (note: just joking)
This answer has the same problem as another answer ("won't work for classes without a default constructor") Also, (for non-trivial types) it will execute the constructor N times (potentially with side effect).
6

You could give Foo a public static constexpr member.

struct Foo {
 static constexpr std::size_t bar_size = 8;
 std::array<int, bar_size> bar;
}

Now you know the size of bar from Foo::bar_size and you have the added flexibility of naming bar_size to something more descriptive if Foo ever has multiple arrays of the same size.

3 Comments

Given the other answers showing this is possible to do without the static const, I don't find this a good answer.
@Tas: To my mind, the issue is that this answer gets things backwards: instead of answering the question of how to get some existing array's number of elements, it says to declare a known number and alter the array's declaration to template it on that. So, the static constexpr member is really not the thing to complain about; it'll consume no space in instances and be completely optimised away in its translation unit (unless its address is taken, but then that would require an out-of-line definition, so).
@Tas @underscore_d Thanks. The reason I made this answer is because the high scoring answers were complicated. The size of bar without the static constexpr is a magic number. This solution removes the magic number and solves the problem with one simple line.
2

You could do it the same as for legacy arrays:

sizeof(Foo::bar) / sizeof(Foo::bar[0])

5 Comments

or use the much more readable std::extent but this isn't an answer as this would still require constructing an instance.
A few other things to keep in mind sizeof std::array<int, 4> may not equal sizeof int[4] that's an implementation detail. Moreover if you're going to construct the std::array then just use the size() member
I meant sizeof(Foo::bar) / sizeof(Foo::bar[0]). No instance of Foo needed.
@Mgetz Don't other, overt requirements of std::array mean that it must have the same size and layout as a raw array in reality, even if that's not explicitly required?
@underscore_d realistically yes, but it's still implementation dependent. As such I wouldn't trust it, there are too many things a compiler can do to mess this up and std::array has a size() member anyway.
-1

Use:

sizeof(Foo::bar) / sizeof(int)

1 Comment

I tried and I am getting the same value for both. #include <iostream> #include <array> using namespace std; struct Foo { std::array<int, 8> bar; }; int main() { cout << sizeof(Foo::bar) / sizeof(int) << endl; cout << std::tuple_size<decltype(Foo::bar)>::value << endl; return 0; }
-5

You can use like:

sizeof Foo().bar

7 Comments

See this comment from OP: he's after the number of elements, not the total size.
@Happy - the OP modified the answer: he want the number of elements in the array (8 in the example), not the sizeof
note: won't work for classes without a default constructor
@M.M Since sizeof doesn't evaluate its operand, you could always just std::declval<Foo>().
@Angew technically std::array is allowed to have padding
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.