Search code examples
c++arrayssizeoftypeof

calculate number of elements from a fixed array (similar to sizeof)


I'm developing a library in C++ in order to give to developers an help to some tasks. Usually, in order to calculate the size of an array of integer (for example) in a dynamic way (without use #define SIZE or static int SIZE), I do sizeof(v) / sizeof(int). I'm trying to write a piece of code that can do for me that stuff automatically and I decided to call if lengthof. The code is here:

template <class T> int _typesize(T*) { return sizeof(T); }
#define lengthof(x) (sizeof(x) / _typesize(&x))

I use the template to get the type of the array, then I return its size in bytes. In GCC I know that it's possible to use typeof, so I can replace _typesize(&x) with sizeof(typeof(x)), but it's not possible on MSVC. _typesize is a compatible way, but I think that it can be expensive because it passes the pointer as copy. There is an elegant way to do this?


Solution

  • No need for macros for this task. If you have a conforming compiler

    template<class T, size_t len>
    constexpr size_t lengthof(T(&)[len]) {return len;}
    //the parameter is an unnamed reference to a `T[len]`, 
    //where `T` is deduced as the element type of the array
    //and len is deduced as the length of the array.
    //similar to `T(*)[len]` in C, except you can pass the array
    //directly, instead of passing a pointer to it.
    //added benefit that if you pass a `T*` to it, it produces a compiler error.
    

    Or if you're using Visual Studio which is not yet conforming...

    template<class T, size_t len>
    std::integral_constant<size_t, len> lengthof(T(&)[len]) {return {};}
    //VC++ doesn't have constexpr, so we have to use `std::integral_constant` instead :(
    //but how it works is 100% identical
    

    If you want a more portable way, macros still work best:

    #define lengthof(arr) sizeof(arr) / sizeof(arr[0])
    //doesn't respect namespaces, evaluates arguments multiple times
    //and if you pass a `T*` to it, it evaluates to `1` depending on context.
    

    But to reiterate my comment, I would consider all of this bad code. Use std::vector or std::array.