0

I'm trying to find the length of any given array and the methods I've tried so far won't work. This is my sizeOf function (not to be confused with sizeof):

template <typename T>
size_t sizeOf(T val) {
    size_t sz = (size_t)0;

    if (typeid(val).name()[0] == 'c') {
        sz = (int)sizeof(val);
    } else if (typeid(val).name()[1] == 'c' || typeid(val).name()[2] == 'c'){
        sz = strlen((const char*)val);
    } else if (typeid(val).name()[0] == 'i') {
        sz = sizeof(val) / 4;
    } else {
        sz = 0; //new code here.
    }
        
    return sz;
}

So far, it works for strings, integers, and characters. The problem is finding the length of any array that isn't of type char. I tried using a for loop and subscripted values (e.g. arr[i]), but this exception occurs when the argument isn't an array: subscripted value is neither an array nor pointer. To this I try a try {...} catch () {...} statement and it still gives this error, so I can't use indices. I also tried another method with pointers: *(&arr + 1) - arr which works without errors, but the values are inconsistent or completely imprecise. Is there a way to acquire the true length of an array without the aforementioned methods and still have a flexible function?

  • 1
    Note that: `typeid(val).name()` - _"...Returns an implementation defined null-terminated character string containing the name of the type. __No guarantees are given__; in particular, the returned string can be identical for several types and change between invocations of the same program...."_ https://en.cppreference.com/w/cpp/types/type_info/name – Richard Critten May 06 '21 at 00:22
  • 2
    Does this answer your question? [Magic arguments in function templates](https://stackoverflow.com/questions/2384107/magic-arguments-in-function-templates) – 273K May 06 '21 at 00:22
  • You want the template overload based on the duplicate. – 273K May 06 '21 at 00:23
  • 1
    Also, `strlen()` does not return the length of the array passed to it. It returns the number of non-nul characters before the first nul (with zero value) character. Assuming a nul terminated string is passed (e.g. a string literal) is passed the array length is one more than the value returned by `strlen()`. It is also possible to construct arrays of `char` in ways that cause `strlen()` to have undefined behaviour, and no amount of checking the type passed will correct that. – Peter May 06 '21 at 00:32
  • Stop using c-arrays completely. Replace them with `std::vector` and/or `std::array` and `std::string` – Richard Critten May 06 '21 at 00:35

2 Answers2

2

Here's a solution that might work for you. It uses if constexpr to ensure that the first template only tries to compile valid branches in the code (you can add more if you need them) and a template overload to handle arrays of arbitrary type. Note: needs C++17 or later.

#include <iostream>
#include <cstring>
#include <type_traits>

template <typename T>
size_t sizeOf (T val)
{
    size_t sz = 0;

    if constexpr (std::is_integral_v <T>)
        sz = sizeof (val);
    else if constexpr (std::is_same_v <T, const char *>)
        sz = strlen (val);
        
    return sz;
}

template <typename T, size_t size>
size_t sizeOf (T (&)[size])
{
    return size;
}

int main ()
{
    int i = 0;
    char c = 0;
    std::cout << "sizeOf int = " << sizeOf (i) << "\n";
    std::cout << "sizeOf char = " << sizeOf (c) << "\n";
    const char *pc = "abcde";
    std::cout << "sizeOf abcde = " << sizeOf (pc) << "\n";
    int a [6];
    std::cout << "sizeOf int [6] = " << sizeOf (a) << "\n";
}

Output:

sizeOf int = 4
sizeOf char = 1
sizeOf abcde = 5
sizeOf int [6] = 6
Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
1
template <typename T>
size_t sizeOf(T const&) {
  return 1;
}

template <typename T,nstd::size_t N>
size_t sizeOf(T const(&)[N]) {
  return N;
}
template <typename T,nstd::size_t N>
size_t sizeOf(std::array<T,N> const&) {
  return N;
}

template <typename T>
size_t sizeOf(T const* val) {
  std::size_t N=0;
  while (val&&val[0]){
    ++N;++val;
  }
  if(val)++N;// include null terminator, makes it comoatible with `"array"` length
  return N
}
Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • If I pass an array (`int a[N]; sizeOf(a);`) I get an error that the call is ambiguous. If I pass an array with a zero as an element (`int a[N]{}; sizeOf(+a);`) I get the wrong length. – David G May 06 '21 at 01:44
  • @0x49 ambiguous fixed I think, I missed a const. The other, well, you are screwed if you aren't using 0 termination. – Yakk - Adam Nevraumont May 06 '21 at 11:47