scobi
scobi

Reputation: 14548

How to have compiler choose static array version of template over pointer?

I'm trying to do something close to this:

template<typename TChar, size_t TSize>
inline size_t StringLength(TChar(&)[TSize])
{
    return TSize - 1;
}

template<typename TChar>
inline size_t StringLength(const TChar* value)
{
    return std::char_traits<TChar>::length(value);
}

...but when calling StringLength("abc"), the compiler finds it ambiguous:

test.cpp(15): could be 'size_t StringLength<char>(const TChar *const )'
with
[
    TChar=char
]
test.cpp(9): or       'size_t StringLength<const char,4>(TChar (&)[4])'
with
[
    TChar=const char
]
while trying to match the argument list '(const char [4])'

(This test was done in VS2013.)

I'd simply like to avoid the strlen when the size is available. Is there a way to do this, or a better option than what I'm attempting?

Upvotes: 8

Views: 166

Answers (2)

T.C.
T.C.

Reputation: 137315

Just take the pointer by const reference, which blocks the array-to-pointer conversion during template argument deduction:

template<typename TChar>
inline size_t StringLength(const TChar* const & value)
                                      //^^^^^^^
{
    return std::char_traits<TChar>::length(value);
}

Demo.

Upvotes: 3

Wintermute
Wintermute

Reputation: 44043

This way works:

#include <cstddef>
#include <iostream>
#include <string>
#include <type_traits>

template<typename TChar, std::size_t TSize>
inline std::size_t StringLength(TChar(&)[TSize])
{
  return TSize;
}

template<typename TCharArray>                   // v-- using SFINAE to disable this overload if TCharArray is not an array type
inline std::size_t StringLength(TCharArray value, typename std::enable_if<!std::is_array<TCharArray>::value, void>::type * = nullptr)
{
  return std::char_traits<typename std::remove_pointer<TCharArray>::type>::length(value);
}


int main() {
  std::cout << StringLength("foo") << "\n";

  char const *ptr = "foo";

  std::cout << StringLength(ptr) << "\n";
}

...but are you sure this is a good idea? I know you want to avoid this discussion, but it's...hard. I mean, consider

char str[100] = "foo";

std::cout << StringLength(str); // will give 100.

It's not exactly POLA-compliant.

Upvotes: 2

Related Questions