Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

templates

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?

like image 528
scobi Avatar asked Dec 09 '14 09:12

scobi


2 Answers

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.

like image 62
T.C. Avatar answered Nov 09 '22 21:11

T.C.


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.

like image 42
Wintermute Avatar answered Nov 09 '22 21:11

Wintermute