如何计算C++模板函数中有效指针元素的总数?

How to count the total number of valid pointer elements in a C++ template function?

在获得 C# 和 Python 的丰富经验后,我最近开始学习 C++。

我正在尝试创建一个接受指针参数的函数模板,然后遍历它的值直到下一个指针元素不再有效。理想情况下,我希望该函数接受一个通用指针参数。值得一提的是,我 不会 能够直接利用底层数组来计算其大小。

我能够为指针的指针实现相同的概念,我在下面包括:

template<class T>
inline constexpr size_t len(const T *pptr[])
{
    if (pptr == nullptr) { return (const size_t)size_t(); }
    const T **begptr = &pptr[0];

    while (*pptr != nullptr)
    {
        pptr++;
    }
    return (const size_t)(pptr - begptr);
}

尝试为普通指针(int *char * 等)实现相同概念的问题在于,我不知道如何在计数器出现后有条件地中断循环不再有效。我希望我能够检查指针地址是否有效,然后相应地中断以便最终计数准确。

我目前拥有的所需功能的伪代码如下:

template<class T>
inline constexpr size_t len(const T *ptr)
{
    if (ptr == nullptr) { return (const size_t)size_t(); }
    const T *begptr = &ptr[0];

    while (/*Pointer is valid*/)
    {
        ptr++;
    }
    return (const size_t)(ptr - begptr);
}

那我有没有可能用一个循环来准确统计有效元素的个数呢?我愿意使用不同的方法,我真的只想要某种接受通用指针并准确计算元素数量的模板函数。

提前感谢大家的宝贵时间和帮助,非常感谢。

template<class T, size_t N>
constexpr size_t size(const T(&)[N])
{
    return N;
}

template<class T>
constexpr size_t len(const T& a)
{
    return std::distance(std::begin(a), 
                         std::find(std::begin(a), std::end(a), 
                                   nullptr));
}

https://godbolt.org/z/r7MhT4

您尝试使用 len() 函数查找 nullptr 元素的操作只能通过 null-terminated 指针数组实现,例如:

int* arr[3];
arr[0] = ... some pointer ...;
arr[1] = ... some pointer ...;
arr[2] = nullptr;

size_t arr_len = len(arr); // returns 3

未能在数组中包含终止 nullptr,您的函数循环将最终进入周围的内存,导致 未定义的行为:

int* arr[3];
arr[0] = ... some pointer ...;
arr[1] = ... some pointer ...;
arr[2] = ... some pointer ...; // <-- not nullptr!

size_t arr_len = len(arr); // undefined behavior!

但是,您的 len() 函数 as-is 不能对 non-pointers 的数组做同样的事情,例如:

int arr[3];
arr[0] = ... some value ...;
arr[1] = ... some value ...;
arr[2] = ... some value ...; // <-- can't assign nullptr here!

size_t arr_len = len(arr); // DOES NOT WORK

您无法将 non-pointers 与 nullptr 进行比较,但您可以将它们与 T default-initializes 进行比较。因此,您将不得不 re-write 该功能。您可以将分配的数组长度作为第二个参数传递,例如:

template<class T>
inline constexpr size_t len(const T pptr[], size_t nump)
{
    if (!pptr) return 0;

    const T *begptr = pptr;

    while ((nump > 0) && (*pptr != T{}))
    {
        ++pptr;
        --nump;
    }

    return (pptr - begptr);
}
int arr[5];
arr[0] = ... some value ...;
arr[1] = ... some value ...;
arr[2] = 0;
arr[3] = ...;
arr[4] = ...;

size_t arr_len = len(arr, 5); // returns 3

或者,您可以通过引用而不是通过指针获取数组,这样您就不会丢失其大小信息,例如:

template<class T, size_t N>
inline constexpr size_t len(const T (&pptr)[N])
{
    const T *begptr = &pptr[0];

    for(size_t i = 0; i < N; ++i)
    {
        if (*pptr == T{}) break;
        ++pptr;
    }

    return (pptr - begptr);
}
int arr[5];
arr[0] = ... some value ...;
arr[1] = ... some value ...;
arr[2] = 0;
arr[3] = ...;
arr[4] = ...;

size_t arr_len = len(arr); // returns 3