std::以原始字符数组结束

std::end with raw arrays of char

本文关键字:数组 结束 字符 原始 std      更新时间:2023-10-16

默认情况下,原始数组的std::end重载如下所示:

template<class T, std::size_t N>
T* end(T (&array)[N])
{ return array + N; }

但是,在传递字符串文字或char数组时,这种重载对我来说是不可取的,因为它们在末尾都有一个隐式,可以计数。

我认为作为一种解决方法,我可以在自己的命名空间中重载end

示例

namespace unique
{
    const char* end(const char (&array)[5])
    {
        return array + 4;
    }
    const char* end(const char (&array)[11])
    {
        return array + 10;
    }
}
int main()
{
    using std::begin;
    using std::end;
    using unique::end;
    const char str1[] = "XXXTEXTXXX";
    const char str2[] = "TEXT";
    auto iter = std::search(begin(str1), end(str1), begin(str2), end(str2));
    //...
}

但是,这将需要大量的重载来编写。

问题

我意识到使用std::string或其他容器可以解决我的问题。但是,我希望能够使用字符串文字或原始数组调用end不合格,并让它省略上面的空终止符。有没有更好的方法来避免写入重载?

显而易见的(如果您确定它只会在适当的情况下使用)将是原始版本的变体:

namespace unique {
template<class T, std::size_t N>
T* end(T (&array)[N])
{ return array + N-1; }
}

只要确保只在正确的情况下使用它,否则你最终会得到end在结束之前指向一个。

如果要将其限制为字符类型,可以使用几个仅适用于字符类型的重载:

namespace unique {
    template <std::size_t N>
    char *end(char (&array)[N])
    {
        return array + N - 1;
    }
    template <std::size_t N>
    wchar_t *end(wchar_t (&array)[N])
    {
        return array + N - 1;
    }
}

这样,char数组将使用假定 NUL 终止符的版本,但int数组将使用 std::end,因此它引用整个数组:

int main()
{
    using std::begin;
    using std::end;
    using unique::end;
    char str1 [] = "12345";
    wchar_t str2 [] = L"12345";
    int i4 [] = { 1, 2, 3, 4, 5, 6 };
    std::cout << std::distance(begin(str1), end(str1)) << "n";
    std::cout << std::distance(begin(str2), end(str2)) << "n";
    std::cout << std::distance(begin(i4), end(i4)) << "n";
}

但是请注意,由于有一个名为 begin 的现有模板,这些重载将只匹配确切的类型,因此如果您希望它们与 const charconst wchar_t 一起使用(例如),则需要与上面处理非 const 类型的重载分开。

另请注意,这些仍然适用于typedef,因此(例如)相当常见的:

typedef char small_int;

。可能/将导致问题 - 实际类型仍然是 char,因此end(my_small_int_array)将使用char重载而不是基本模板。