One loosely related trick I found quite recently is that C++ lets you template on array size, which lets you overload things that take a buffer + size to only take the buffer (can’t do it in plain C), and also lets you implement an ARRAY_COUNT macro that doesn’t compile if you use it on pointers.
template< typename T, size_t N >
char ( &ArrayCountObj( const T ( & )[ N ] ) )[ N ];
#define ARRAY_COUNT( arr ) ( sizeof( ArrayCountObj( arr ) ) )
I believe that declares a function returning an array of N chars? Anyway the error you get is crap but it does work (int * a; ARRAY_COUNT( a )):
main.cc: In function ‘int main()’:
main.cc:5:57: error: no matching function for call to ‘ArrayCountObj(int*&)’
#define ARRAY_COUNT( arr ) ( sizeof( ArrayCountObj( arr ) ) )
^
main.cc:9:9: note: in expansion of macro ‘ARRAY_COUNT’
return ARRAY_COUNT( a );
^~~~~~~~~~~
main.cc:4:9: note: candidate: template<class T, long unsigned int N> char (& ArrayCountObj(const T (&)[N]))[N]
char ( &ArrayCountObj( const T ( & )[ N ] ) )[ N ];
^~~~~~~~~~~~~
main.cc:4:9: note: template argument deduction/substitution failed:
main.cc:5:57: note: mismatched types ‘const T [N]’ and ‘int*’
#define ARRAY_COUNT( arr ) ( sizeof( ArrayCountObj( arr ) ) )
^
main.cc:9:9: note: in expansion of macro ‘ARRAY_COUNT’
return ARRAY_COUNT( a );
^~~~~~~~~~~
Cool! If you can use a C++14 compiler (C++11 is probably good enough, but can’t recall the history of constexpr rules), you can write a constexpr function template which does the same:
Unfortunately C++ (e.g. template< typename T, size_t N > char ( &ArrayCountObj( const T ( & )[ N ] ) )[ N ];) is unreadable with syntax highlighting too.
Note that with some GCC extensions you can implement an array-count macro that rejects pointers (or any non-array type, really) in C…from the Linux kernel:
I guess it could be used as a more succinct way of getting a pointer to the end of a C array. Though it’s mostly in C++ that you use begin and end instead of pointer and size (and in C++ you have std::end for this):
int arr[3] = { 7, 3, 5 };
// These all do the same
std::sort(arr, (&arr)[1]);
std::sort(arr, arr + sizeof(arr) / sizeof(arr[0]));
std::sort(std::begin(arr), std::end(arr));
One loosely related trick I found quite recently is that C++ lets you template on array size, which lets you overload things that take a buffer + size to only take the buffer (can’t do it in plain C), and also lets you implement an ARRAY_COUNT macro that doesn’t compile if you use it on pointers.
I believe that declares a function returning an array of N chars? Anyway the error you get is crap but it does work (
int * a; ARRAY_COUNT( a )
):Cool! If you can use a C++14 compiler (C++11 is probably good enough, but can’t recall the history of constexpr rules), you can write a constexpr function template which does the same:
(ideone)
As for the error message, I wonder if you could do something nasty with SFINAE and
static_assert
to improve that.OT, we need colorized syntax highlighting on Lobsters.
Unfortunately C++ (e.g.
template< typename T, size_t N > char ( &ArrayCountObj( const T ( & )[ N ] ) )[ N ];
) is unreadable with syntax highlighting too.Note that with some GCC extensions you can implement an array-count macro that rejects pointers (or any non-array type, really) in C…from the Linux kernel:
This old Reddit comment explains what’s going on: https://www.reddit.com/r/programming/comments/1scchh/the_difference_between_arr_and_arr_how_to_find/cdwjgup/
tl;dr: the size of the array is contained in the array pointer’s type
I guess it could be used as a more succinct way of getting a pointer to the end of a C array. Though it’s mostly in C++ that you use begin and end instead of pointer and size (and in C++ you have
std::end
for this):