15

Given a builtin array x of arbitrary type T, there are functions std::begin() and std::end() that I can call, but why isn't there a std::size()? Seems odd not to have that.

I could use std::end(x)-std::begin(x), but still a std::size(x) would be better.

Yes, I know of the std::vector and std::array classes. This is just a question of why something as simple as this isn't available as yet in the STL.

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
Adrian
  • 10,246
  • 4
  • 44
  • 110
  • There is std::distance, similar to what your looking for – aaronman Oct 08 '13 at 20:54
  • Should `std::size` only work for a type if it is cheap, or should it work regardless? – Yakk - Adam Nevraumont Oct 08 '13 at 21:15
  • @Yakk Good question. Probably regardless. I believe all container types have a size() function? – Adrian Oct 08 '13 at 22:01
  • I am not privy to their decision making, but I would hazard a guess as to why there is no such function is because it would be a function that would only really be useful for C-style arrays, which are highly discouraged and for which they created a new type specifically to replace. At the very least it would be a really low priority. – Gerald Oct 08 '13 at 22:11
  • 1
    @Gerald Then why bother with `std::begin()` and `std::end()`? – Adrian Oct 08 '13 at 22:15
  • To facilitate iteration on other types that don't have begin and end member functions, such as std::valarray. – Gerald Oct 08 '13 at 22:21
  • 2
    @Gerald: That's a weak argument, one could add `std::valarray::begin`. The only container for which you can't add such a member is `T[]`. – MSalters Oct 08 '13 at 22:25
  • You also can't add begin and end member functions to types for which you don't have the source code, or the authority to modify. But you can create free function specializations, so you can still use standard algorithms in a consistent manner without having to create an adapter. This is a much more common use case than a type that does not expose it's size. – Gerald Oct 08 '13 at 22:34
  • @Adrian most specifically, in order to support `for( auto&& x:c )` loops on an arbitrary type, we needed some way to express "get a begin and end iterator from `c`". `std::begin` and `std::end` are ways you can get such a begin and end iterator from an arbitrary type without having to modify that type, including C style arrays. Is there a case similar to this for `std::size`? Now, I wouldn't be against proposing adding it to the standard: but the case for `std::begin` and `std::end` rests on the `for( : )` loop. – Yakk - Adam Nevraumont Oct 08 '13 at 23:32
  • @Yakk, so your saying that the *only* reason for `std::begin` and `std::end` is because of `for( : )`? `for( : )` is totally unnecessary, and could have been dealt with using an algorithm and a lambda function and requiring the object to have a `begin` and `end` function. – Adrian Oct 09 '13 at 06:19
  • @Yakk `std::begin` and `std::end` aren't used for `for( : )` loops over plain old arrays. –  Oct 09 '13 at 08:36
  • @hvd Are you saying that `std::begin` and `std::end` are used for all other containers when using `for( : )`? – Adrian Oct 09 '13 at 12:39
  • @Adrian No, I'm not: for containers that are arrays, there's special support that doesn't require any function. For containers with `begin()`/`end()` member functions, those member functions get used. Only for containers (or "ranges" to use the standard's term) that aren't arrays *and* don't have `begin()`/`end()` member functions do `begin(range)` and `end(range)` get used. –  Oct 09 '13 at 13:02
  • @hvd true, but IIRC the original design did that, and up to an `include` they are almost identical (if someone specializes or overrides begin on a container with begin they differ. – Yakk - Adam Nevraumont Oct 09 '13 at 13:29
  • @Yakk That's probably the reason, too: in order to define and use a plain old array, no standard headers have ever been necessary, so it's nice that new language constructs don't add any requirements. –  Oct 09 '13 at 13:57
  • 1
    You can use boost::size() http://stackoverflow.com/a/8266602/61505 – KindDragon Sep 10 '14 at 09:16

4 Answers4

28

Just a note to let people know that N4280 "Non-member size() and more (Revision 2)" has been accepted into the C++17 Working Draft. This includes std::size() as well as std::empty() and std::data().

Ricky65
  • 1,657
  • 18
  • 22
16

There's std::extent, which is to be applied to the type of the array:

#include <type_traits>

int a[12];

assert(std::extent<decltype(a)>::value == 12);

Alternatively you can use std::distance(std::begin(a), std::end(a)).

The former is manifestly a constant expression, though in practice the latter can be comuted statically as well.

Finally, there's always the homegrown solution:

template <typename T, std::size_t N>
constexpr std::size_t array_size(T const (&)[N])
{ return N; };
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 2
    Yeah, I know about the homegrown version. I was just wondering why it wasn't in the STL. Thanks for the `std::extent` method. – Adrian Oct 08 '13 at 21:08
  • @Adrian: I suppose there isn't such a general use for this... most times you need the size, you want to iterate over the array, which you can do in other ways. But, maybe it'll be added at some point. – Kerrek SB Oct 08 '13 at 21:27
  • 1
    `std::size()` would be useful if one wanted to declare multiple arrays of the same length in which the length of the first was determined via list-initialization. – Joshua Green Aug 10 '14 at 23:44
  • @JoshuaGreen: You mean "if you want to declare multiple arrays *in the same statement*". Yes, that's true, but also trivially worked around :-) – Kerrek SB Aug 11 '14 at 07:21
  • I actually meant in separate statements. `int array1[] = {0, 1, 2, 3, 4}; int array2[sizeof(array1)/sizeof(array1[0])];` is what I use now, but arguably something like `std::size()` would make this "cleaner." – Joshua Green Aug 11 '14 at 12:02
  • 6
    @JoshuaGreen: There's a [pending proposal](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4017.htm) for a free `std::size` function (as well as `std::empty`). – Kerrek SB Aug 11 '14 at 12:18
  • @KerrekSB: I believe it's time it gets an update with C++17's `std::size()`. Ref: https://en.cppreference.com/w/cpp/iterator/size. – Azeem Aug 09 '18 at 16:25
  • 1
    @Azeem: well, the question is tagged as `c++11` :-) – Kerrek SB Aug 09 '18 at 19:44
2

STL algorithm works on iterators, not on any container, size of a STL container would need a start and end, that won't make sense. For such we already have std::distance

P0W
  • 46,614
  • 9
  • 72
  • 119
  • One can do: `int x[] = {1,2,3,4,5}; for_each(std::begin(x), std::end(x), [](int element) { std::cout << element << std::endl; });` Which shows it can use STL algorithms. – Adrian Oct 08 '13 at 20:59
  • 1
    @Adrian: Why not `for (int element : x) std::cout << element << std::endl;`? – Kerrek SB Oct 08 '13 at 21:00
  • @Adrian I'm sorry I didn't get the context, what can use STL algorithm ? – P0W Oct 08 '13 at 21:01
  • @KerrekSB Yeah, that is also another option. – Adrian Oct 08 '13 at 21:02
  • @POW, I actually didn't say use a STL algorithm in my question, but arrays can be used as a container in the context of the STL algorithm library using a pointer as the iterator. `std::begin(x)` is equivalent to `std::vector y; y.begin()`. – Adrian Oct 08 '13 at 21:06
  • @KerrekSB I was just showing that it can be used with the STL. – Adrian Oct 08 '13 at 21:07
  • @Adrian free functions `std::begin` & `std::end` returns iterators, so if you think you are directly operating on container x, you're wrong. Also _"This is just a question of why something as simple as this isn't available as yet in the STL."_, right ? – P0W Oct 08 '13 at 21:14
  • @POW, yes, I know there is a separation between iterators and containers. This keeps the code from exploding trying to write algorithms for every container. You only need to write for iterators. However, containers have functions to return iterators, and have a way of returning size. I was asking why a size() function wasn't made available to be equivalent to a *container's* size, not any algorithm. Basically a specialization for builtin arrays like all of the other containers have. – Adrian Oct 08 '13 at 21:58
0

I suppose you mean C-like arrays. The answer, as Bjarne Stroustrup said, is because "An array in C is a data type that is so stupid that it didn't even know how many elements it got." Once an array decays to a pointer there is no way to know how many elements where there in the 'array'.

Marius Bancila
  • 16,053
  • 9
  • 49
  • 91
  • Where did Bjarne Stroustrup say that? A quick search doesn't bring up that quote anywhere. It seems bogus to me: the information remains available so long as you work with the array type. Only once you stop working with the array type, the information is lost. –  Oct 08 '13 at 21:10
  • 1
    Bjarne Stroustrup - The Essence of C++: With Examples in C++84, C++98, C++11, and C++14 at GoingNative 2013 http://channel9.msdn.com/Events/GoingNative/2013/Opening-Keynote-Bjarne-Stroustrup at 49:19. – Marius Bancila Oct 08 '13 at 21:15
  • Thanks. No wonder a search didn't bring that up, if it hasn't been transcribed. :) It still seems bogus to me, though. –  Oct 08 '13 at 21:18
  • 1
    But you can easily get the size by not allowing it to decay into a pointer (which is what `std::begin` and `std::end` do). – juanchopanza Oct 08 '13 at 21:23