I'm working with/learning template function specialization rules. I start with this function
template<typename T>
std::string toString(const T& t)
{
ostringstream out;
out << t;
return out.str();
}
Now I'd like to specialize it for const char*
typedef const char* ccharPtr;
template<>
std::string toString(const ccharPtr& s)
{
cout << "in specialization" << endl; // just to let me know
return std::string(s);
}
I'd like to do that without a typedef, but so far I can't figure it out.
That specialization works for a const char*, but not for a char*.
const char* s1 = "Hi"
cout << toString(s1); // works
char s2[] = "There";
cout << toString(s2); // doesn't work, since s2 isn't const char*
cout << toString(", Bob"); // doesn't work. Why not?
I'd like a single specialization to work for each case, but having trouble figuring it out.
Why specialise? Just overload the function. Fully specialising function templates is usually not required.
OK, if you really want to do this, then you have to consider that the type of string literals — although they implicitly convert to
char const*
— ischar const[N]
.Live demo.
You can omit specialisation
S2
, and then both"There"
and", Bob"
will useS3
.Be warned that, actually, this isn't specialisation at all. I've rather cheated by creating new function templates. But I had to to get the
size_t
parameter in; you could only do real specialisation here if you picked one value forN
and wrote it into the function signature as part of a concrete type, or if you could partially specialise function templates.I think this should work:
The reason it doesn't work is because it's not actually the right type. String literals are not of type
const char*
, they are of typeconst char[N]
. When you pass a string literal, then T is deduced to bechar[N]
. This is an exact match and the specialization is not. You cannot speciailize for string literals, as that would require a partial spec and C++ does not support partial function specializations.I had a similar problem with Sun Studio C++ compiler.
At first, I used two array overloads (
char (&)[N]
with and withoutconst
) and two pointer overloads (char*
andconst char*
).To my surprise for calls like
toString("quoted literal")
theconst char*
was used and it seemed impossible to force the compiler to choose the array overload. What is even more interesting - for arguments likechar lit[] = "literal"
,toString(lit)
chose the array overload!After some thought, I found a way to have a code which behaves as partial function specializations. The trick is to make use of SFINAE
First, define a template to distinguish
(const) char*
from(const) char[N]
Inner typedef
type
acts likeenable_if
andptr_type
likedisable_if
We can use
is_literal
to implement the functions:Some compilers may have problems with
const
- for thoseconst T& arg
overloads might be needed.I use this solution mainly for performance reasons when I have frequently called functions and want to save
strlen
calls or replacestrcpy
with simplememcpy