3

Possible Duplicate:
How does this “size of array” template function work?

Is there any possibility to implement NARR without a macro in C++ (C++0x)?

const static pair<string,int> data[] = {
    {"Montag",1}, {"Dienstag",2}, {"Mittwoch",3}, {"Donnerstag",4},
    {"Freitag",5}, {"Samstag",6}, {"Sonntag",7}
};
#define NARR(A) (sizeof(A)/sizeof(*A))
const static map<string,int> german_weekdays(data, data+NARR(data));

A simple function is not possible, because then the [] loses its size-information and becomes just another poiner:

size_t narr(sometype arr[]) { /* won't work */ }

Templates? Overloading? Magic?

Community
  • 1
  • 1
towi
  • 21,587
  • 28
  • 106
  • 187

3 Answers3

9

It is possible in C++:

template< typename T, std::size_t Size >
std::size_t size(const T (&)[Size])
{
  return Size;
}

The advantage of this over the macro solution is that the compiler will cough up a nasty error message if you try to pass a pointer to this.

sbi
  • 219,715
  • 46
  • 258
  • 445
  • There's a way to get a compile-time constant, too, but it makes my head spin, so I work hard on forgetting it each time I see it. And it does need a macro to be usable. – sbi Apr 05 '11 at 07:53
  • http://stackoverflow.com/questions/3368883/how-does-this-size-of-array-template-function-work/3368894#3368894 – GManNickG Apr 05 '11 at 08:07
  • @GMan: Ah, didn't remember that one. Wow, and it's closed as a dupe of two others, the second of which is closed as a dupe of the first one... That's quite a genesis. Shouldn't we make one of these an FAQ entry? – sbi Apr 05 '11 at 09:11
  • but this *is* compile-time constant. Isn't it? Ah, no, it isn't, but it will be, thanks to `constexpr` :-) – towi Apr 05 '11 at 10:23
  • 1
    @towi: Indeed, `constexpr` does that (and much better than the unreadable hack which does the same for C++03). Also, see Steve's answer. If you still don't have `std::end()`, you can easily make it yourself: http://stackoverflow.com/questions/2552839/which-c-standard-library-wrapper-functions-do-you-use/2553081#2553081 – sbi Apr 05 '11 at 12:04
4

In C++0x:

#include <iterator>

const static map<string,int> german_weekdays(data, std::end(data));

Also you can use std::begin(data) if you like, for symmetry or genericness[*]. And possibly you can use an initializer list instead of an array anyway...

[*] Although for full genericness, you should probably do:

using std::begin;
using std::end;
begin(data), end(data);

The reason is that the new "range-based for loop" syntax is equivalent to using begin and end without qualification, but with std as an associated namespace for ADL. So as with std::swap, authors of types might provide begin and end functions that are intended to be found via ADL. They probably ought to provide begin() and end() member functions instead, which std::begin and std::end will call. But if they provide something that works with ranged-based for, and doesn't work with your code, then you'll have to have an argument who should change.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • I think with ADL and the range-based-for there might be a change, very recently. We will see. And I don't like `using`s much, I'd rather be specific where I need the item. But anyway: Great tip about using `begin()` and `end()`, I (obviously) did not think of that in this context. Great. – towi Apr 05 '11 at 10:22
  • @towi: yes, I haven't checked the FDIS, and in the end it'll be programming convention that determines what classes are expected to provide, not the standard alone. The important innovation was to make `begin` and `end` free functions at all, that's what allows them to work for arrays. – Steve Jessop Apr 05 '11 at 10:29
2

I can't test this right now, because I've been away for a while and the latest GCC 4.6 just refused to compile, but constexpr should make short work of the question. Of course, it's better to sidestep this issue using Steve's suggestion.

template< typename T, size_t N >
constexpr size_t narr( T const (&)[ N ] )
    { return N; }
Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • For getting newest gcc versions, usually you can just download the daily compiled snapshot of mingw-w64. It currently contains gcc4.7 trunk even. They are precompiled even for linux hosts. Just unpack them and run the binaries. Code produced can be run with windows or wine. Nothing easier than that :) – Johannes Schaub - litb Apr 05 '11 at 14:22
  • @Johannes: My tree was set up for contribution to libstdc++-v3 as of October, so I need to figure out which branch I need to be on and then get restarted, if I really have time even now. Also, I'm on Mac OS/Darwin. Thanks anyway, though, and glad to see you are still here and well! – Potatoswatter Apr 05 '11 at 15:11