57

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?

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
ChronoTrigger
  • 8,459
  • 1
  • 36
  • 57

6 Answers6

91

You may use std::tuple_size:

std::tuple_size<decltype(Foo::bar)>::value
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • 16
    Hooking this here: the various classes and functions dealing with `std::tuple`s (`std::tuple_size`, `std::tuple_element`, `std::get`) have handy specializations to treat an `std::array` like a `std::tuple`. – Quentin Dec 27 '16 at 13:20
  • Can be simplified in C++17 to `std::tuple_size_v` – Becon Jul 28 '23 at 05:19
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.

Community
  • 1
  • 1
skypjack
  • 49,335
  • 19
  • 95
  • 187
  • 2
    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 Dec 27 '16 at 13:22
  • 5
    @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. – skypjack Dec 27 '16 at 13:26
  • 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 Dec 27 '16 at 13:30
  • 3
    @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) – skypjack Dec 27 '16 at 13:33
  • This answer has the same [problem](https://stackoverflow.com/questions/41345182/get-size-of-stdarray-without-an-instance#comment69892592_41345330) 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). – user202729 Feb 08 '20 at 05:02
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.

Willy Goat
  • 1,175
  • 2
  • 9
  • 24
  • Given the other answers showing this is possible to do without the `static const`, I don't find this a good answer. – Tas Dec 28 '16 at 18:41
  • @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). – underscore_d Dec 29 '16 at 02:14
  • @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. – Willy Goat Dec 31 '16 at 00:31
3

You could do it the same as for legacy arrays:

sizeof(Foo::bar) / sizeof(Foo::bar[0])
Tas
  • 7,023
  • 3
  • 36
  • 51
Waxrat
  • 2,075
  • 15
  • 13
  • 3
    or use the much more readable [`std::extent`](http://en.cppreference.com/w/cpp/types/extent) but this isn't an answer as this would still require constructing an instance. – Mgetz Dec 27 '16 at 12:59
  • 4
    A few other things to keep in mind `sizeof std::array` may not equal `sizeof int[4]` that's an implementation detail. Moreover if you're going to construct the [`std::array`](http://en.cppreference.com/w/cpp/container/array) then just use the [`size()`](http://en.cppreference.com/w/cpp/container/array/size) member – Mgetz Dec 27 '16 at 13:33
  • 2
    I meant `sizeof(Foo::bar) / sizeof(Foo::bar[0])`. No instance of Foo needed. – Waxrat Dec 27 '16 at 13:40
  • @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 Dec 27 '16 at 20:22
  • 2
    @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. – Mgetz Dec 28 '16 at 14:08
0

Use:

sizeof(Foo::bar) / sizeof(int)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Gilson PJ
  • 3,443
  • 3
  • 32
  • 53
  • I tried and I am getting the same value for both. `#include #include using namespace std; struct Foo { std::array bar; }; int main() { cout << sizeof(Foo::bar) / sizeof(int) << endl; cout << std::tuple_size::value << endl; return 0; }` – Gilson PJ Dec 27 '16 at 13:14
-4

You can use like:

sizeof Foo().bar
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Happy
  • 3
  • 5