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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With