0

If I call this function:

template <typename t>
size_t
Foo(const T& str) {
  return std::distance(std::begin(str), std::end(str));
}

... with these three types:

const auto a = "abc";
const char b[3] = {'a', 'b', 'c'};
const std::string c("abc");

The first type will return 4 (including the null), and the other ones returns 3. How can I distinguish these types so that they all return three (as is the number of characters)?

Viktor Sehr
  • 12,825
  • 5
  • 58
  • 90
  • You cannot, unfortunately, distinguish a string literal from any other array of `const char`s. That is a limitation of the language. – Kerrek SB Mar 09 '14 at 22:01
  • You can, for example, check if the last character is a `'\0'` (for an array of `char`). This of course extends to `'\0'` at arbitrary positions within the array. – dyp Mar 09 '14 at 22:05
  • @KerrekSB `constexpr` allows for a check of the last byte at compile time, but that doesn't account for 1) when the string has been converted to `char *`, or 2) when it contains an internal NUL byte. – Potatoswatter Mar 09 '14 at 22:11
  • @Potatoswatter: Exactly. In other words, you cannot distinguish string literals specifically from const-char arrays in general :-S – Kerrek SB Mar 09 '14 at 22:14

1 Answers1

0

The string literal "abc" includes a null terminator byte. The declaration of a is the same as if it were

char a[] = { 'a', 'b', 'c', '\0' };

If you want not to count the termination, or characters following it, you could use std::strlen. However, this relies on the existence of that byte and it could crash when given b. You could make an overload set:

template< typename t >
std::size_t string_length( t const & s ) {
    return s.size();
}

std::size_t string_length( char const * s ) { // requires a termination byte!
    return std::strlen( s );
}

template< std::size_t n > // requires the name of the array to be passed!
std::size_t string_length( char const (&s)[n] ) {
    return std::find( &* s, s + n, '\0' ) - s;
}

This is however a very dangerous practice because if you assign the b array to a char * variable, that variable will select the second overload, but the terminator byte is missing.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421