Reputation: 6916
I have the following code for a "safe" strncpy() -- basically it's wrapper automatically takes fixed array sizes for string buffers so you don't have to do the extra work to pass them in (and this convenience is safer because you won't accidentally type the wrong size for fixed array buffers).
inline void MySafeStrncpy(char *strDest,size_t maxsize,const char *strSource)
{
if(maxsize)
{
maxsize--;
strncpy(strDest,strSource,maxsize);
strDest[maxsize]=0;
}
}
inline void MySafeStrncpy(char *strDest,size_t maxDestSize,
const char *strSource, size_t maxSourceSize)
{
size_t minSize=(maxDestSize<maxSourceSize) ? maxDestSize:maxSourceSize;
MySafeStrncpy(strDest,minSize,strSource);
}
template <size_t size>
void MySafeStrncpy(char (&strDest)[size],const char *strSource)
{
MySafeStrncpy(strDest,size,strSource);
}
template <size_t sizeDest,size_t sizeSource>
void MySafeStrncpy(char (&strDest)[sizeDest],
const char (&strSource)[sizeSource])
{
MySafeStrncpy(strDest,sizeDest,strSource,sizeSource);
}
template <size_t sizeSource>
void MySafeStrncpy(char *strDest,size_t maxDestSize,
const char (&strSource)[sizeSource])
{
MySafeStrncpy(strDest,maxDestSize,strSource,sizeSource);
}
Using the code results in an error in Visual C++ 2008 when compiling:
char threadname[16];
MySafeStrncpy(threadname,"MainThread");
error C2668: 'MySafeStrncpy' : ambiguous call to overloaded function
> could be 'void MySafeStrncpy<16,11>(char (&)[16],const char (&)[11])'
> or 'void MySafeStrncpy<16>(char (&)[16],const char *)'
> while trying to match the argument list '(char [16], const char [11])'
What am I doing wrong here?
It seems like the compiler is unable to determine if the character string literal "MainThread"
should be treated as a const char *
or a const char[11]
when determining which template function to call.
I would like it to treat the string literal as a const char[11]
and select the void MySafeStrncpy<16,11>(char (&)[16],const char (&)[11])
variant since that is the "safest".
Also two more constraints on answers: 1) I am unable to switch compilers (the code compiles on other compilers) and 2) the company will not allow me to use external template libraries for a solution.
Upvotes: 4
Views: 2459
Reputation: 5279
You cannot have two function overloads for char pointers and char arrays, but you can have two class template specializations:
template<typename StringConstant>
class Impl
{
auto operator()(const StringConstant& str) = delete;
}
template<typename Elem>
[[deprecated("Passing char pointer without length is unsafe")]]
class Impl<const Elem*>
{
auto operator()(const Elem* str) -> ...
{ ... }
}
template<typename Elem, std::size_t Size>
class Impl<const Elem[Size]>
{
auto operator()(const Elem str[Size]) -> ...
{
// Remember that length of str is Size - 1 (don't include null character)
...
}
}
template<typename StringConstant>
auto func(const StringConstant& str) -> ...
{
return Impl<StringConstant>()(str);
}
// Need function overload for C arrays.
// When used as rvalue expressions, arrays decay to pointers to the first element.
// See https://stackoverflow.com/a/9128891/2279059
template<typename Elem, std::size_t Size>
auto func(const Elem(&str)[Size]) -> ...
{
return Impl<Elem[Size]>()(str);
}
Note that you really shouldn't need any of this for anything other than backwards-compatibility. Instead of a constant C character array, just use a static const
string, and the only reason to accept raw char pointers anywhere is for compatibility with old code or third-party libraries. If you need functions to accept "any kind of string constant", better use std::basic_string_view
.
Upvotes: 0
Reputation: 5073
When u are using your function :
MySafeStrncpy(threadname,"MainThread");
you are not passing the size_t argument in between threadname & "MainThread", but u have defined in function definition.
it shud be something like this :
MySafeStrncpy(threadname, sizeof threadname, "MainThread");
if u dont want to pass the argument then make it default in ur function definition.
Upvotes: 0
Reputation: 11669
According to 13.3.3.1.1, Array-to-pointer conversion has Exact Match rank, so this function call might be ambiguous in the standard spec. If you are allowed to change the definition:
template <size_t size>
void MySafeStrncpy(char (&strDest)[size],const char *strSource)
to:
template <size_t size, class T>
void MySafeStrncpy(char (&strDest)[size], T strSource)
like here, then probably that'll be the simplest workaround.
Upvotes: 2
Reputation: 36049
The overloads for char-array/const-char-array and char-array/const-char-pointer can't be distinguished from each other by overload resolution logic (at least the Microsoft logic - this code compiles just fine in GCC. Don't know that the standard says here.). You need to distinguish them in some way, e.g. by renaming the function for arrays or adding a dummy parameter.
An elegant solution would be using boost::enable_if and boost::is_array.
Upvotes: 0