3

By default, the std::end overload for raw arrays looks something like this:

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

However, this overload was undesirable for me when passing a string literal or a char array, as they both have an implicit \0 at the end which gets counted.

I thought as a workaround I could overload end in my own namespace:

Example:

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));
    //...
}

However, that would require a lot of overloads to write.

QUESTION

I realize using std::string or another container would solve my problem. However, I wanted to be able to call end unqualified with a string literal or raw array and have it omit the null terminator as above. Is there a better approach that would avoid writing the overloads?

4

1 回答 1

5

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

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;
    }
}

这样,数组 ofchar将使用假定 NUL 终止符的版本,但数组 ofint将使用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 char并且const wchar_t(例如)这些将需要与上面使用非 const 类型的重载分开.

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

typedef char small_int;

...可以/将导致问题——真正的类型仍然是 char,所以end(my_small_int_array)将使用char重载而不是基本模板。

于 2013-09-11T03:54:21.237 回答